【问题标题】:java GZIPInputStream and GZIPOutputStream not working as expectedjava GZIPInputStream 和 GZIPOutputStream 没有按预期工作
【发布时间】:2016-11-01 09:19:50
【问题描述】:

我正在尝试将一系列Long 写入GZIPOutputStream,希望以后能解压这些数字。
当我尝试使用少量Long 时,以下程序运行良好,但它会抛出许多Long 的异常,例如(10240)。

请查看并运行此代码:

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)

【问题讨论】:

  • 您遇到了什么问题?注意:read 只保证读取 1 个字节(或更多) 为什么不使用 DataOutputStream 和 writeLong/readLong 或使用 readFully 始终读取 8 个字节。
  • @PeterLawrey 上面的程序在我尝试解压缩一些Long 时工作正常,比如32,但是当我尝试很多Long 时就不行了,比如10240.
  • “行不通”是什么意思? --- 另外,在bytes2long 中,您应该只使用return ByteBuffer.wrap(bytes).getLong();
  • 我的意思是为什么test(32); 通过但test(10240); 抛出异常。
  • @PeterLawrey 现在我明白你的意思了。 read 不保证完整阅读。你说的对。谢谢大佬!

标签: java compression gzipinputstream gzipoutputstream


【解决方案1】:

如果您按照 Peter 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);
            }
        }
    }

【讨论】:

  • 我担心 DataInputStream 可能会有一些开销。此外,这是与GZIPInputStream 合作的唯一方法吗?
  • DataInputStream 的开销比您为每个 long 使用新的 ByteBuffer 读取/写入 long 的方式要少。 DataInputStream 提供了很好的方法readLong() with 为你做所有事情。因此,您只需要 DataInputStream 和 DataOutputStream 来读取和写入 long 值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-28
  • 1970-01-01
  • 2016-08-13
相关资源
最近更新 更多