0

Я пытаюсь написать серию Long на GZIPOutputStream, надеясь разложить номера позже.
Следующая программа отлично работает, когда я пытаюсь использовать ее с небольшим количеством Long, но это вызовет исключение со многими Long, например (10240).java GZIPInputStream и GZIPOutputStream работают не так, как ожидалось

Пожалуйста, смотрите и запустить этот код:

import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.nio.ByteBuffer; 
import java.util.zip.GZIPInputStream; 
import java.util.zip.GZIPOutputStream; 

public class GzipTest { 
    private static final String filename = "data.gz"; 

    public static void main(String... args) throws Exception { 
     test(32); // OK 
     test(10240); // Why won't this work? (unexpected read: 6) 
    } 

    public static void test(int max) throws Exception { 
     System.out.println("testing with " + max); 
     FileOutputStream fos = new FileOutputStream(filename); 
     GZIPOutputStream gos = new GZIPOutputStream(fos, 4096); 
     long num = 10241000L; 
     for (int i = 0; i < max; ++i) { 
      gos.write(long2bytes(num + i)); 
     } 
     gos.close(); 
     fos.close(); 

     GZIPInputStream gis = new GZIPInputStream(new FileInputStream(filename), 4096); 
     byte[] buf = new byte[Long.BYTES]; 
     for (int i = 0; i < max; ++i) { 
      int nread = gis.read(buf); 
      if (nread != Long.BYTES) { 
       throw new RuntimeException("unexpected read: " + nread); 
      } 
      long value = bytes2long(buf); 
      if (value != num + i) { 
       throw new RuntimeException("unexpected value: " + value); 
      } 
     } 
     gis.close(); 
    } 

    static byte[] long2bytes(long num) { 
     ByteBuffer buf = ByteBuffer.allocate(Long.BYTES); 
     buf.putLong(num); 
     return buf.array(); 
    } 

    static long bytes2long(byte[] bytes) { 
     return ByteBuffer.wrap(bytes).getLong(); 
    } 
} 

Выходы:

testing with 32 
testing with 10240 
Exception in thread "main" java.lang.RuntimeException: unexpected read: 6 
    at GzipTest.test(GzipTest.java:31) 
    at GzipTest.main(GzipTest.java:12) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) 
+3

В чем проблема? Примечание. Чтение гарантируется только для чтения 1 байт (или более). Почему бы не использовать DataOutputStream и writeLong/readLong или использовать readFully, чтобы всегда читать 8 байтов. –

+0

@PeterLawrey Приведенная выше программа отлично работает, когда я пытаюсь сжать несколько «длинных», например 32, но не буду работать, когда я пробую много «Длинных», например 10240. – adamsmith

+0

Что «выиграет» «работа»? --- Также, в 'bytes2long', вы должны просто использовать' return ByteBuffer.wrap (bytes) .getLong(); '. – Andreas

ответ

1

Th код работает без каких-либо проблем, если вы сделаете изменения, предложенные Петром Lawrey:

try (DataInputStream in = new DataInputStream(new GZIPInputStream(new FileInputStream(filename), 4096))) { 
     byte[] buf = new byte[Long.BYTES]; 
     for (int i = 0; i < max; ++i) { 
      in.readFully(buf); 
      long value = bytes2long(buf); 
      if (value != num + i) { 
       throw new RuntimeException("unexpected value: " + value); 
      } 
     } 
    } 

Или вы можете упростить все до:

try (DataInputStream in = new DataInputStream(new GZIPInputStream(new FileInputStream(filename), 4096))) { 
     for (int i = 0; i < max; ++i) { 
      long value = in.readLong(); 
      if (value != num + i) { 
       throw new RuntimeException("unexpected value: " + value); 
      } 
     } 
    } 
+0

Я боюсь, что с DataInputStream могут возникнуть некоторые накладные расходы. Кроме того, это единственный способ работать с 'GZIPInputStream'? – adamsmith

+0

Накладные расходы с DataInputStream меньше, чем ваш способ читать/писать долго, используя новый ByteBuffer для каждого длинного. DataInputStream предлагает отличный метод 'readLong()', который делает все для вас. Поэтому вам нужны DataInputStream и DataOutputStream для чтения и записи длинных значений. – Robert

 Смежные вопросы

  • Нет связанных вопросов^_^