【问题标题】:Strange behavior in GZIPOutputStream/GZIPInputStreamGZIPOutputStream/GZIPInputStream 中的奇怪行为
【发布时间】:2017-09-29 18:24:22
【问题描述】:

我已将这段代码中的奇怪问题降至最低。该程序将 (int)90000 字节的 128,000 倍写入文件,然后尝试将其读回。

设置 zipped=false 一切都像魅力一样 设置 zipped=true ,直到第 496 个 1024 字节块为止,一切都像一个魅力。此时一个字节丢失,所有内容都向左移动一个字节(见输出)

...
0 1 95 -112- 是 int 90,000 的字节码
专柜:496 126937
1 95 -112 0- 这是 int 23,040,000 的字节码
...

这是我想出的代码。我只是不明白为什么它会在一遍又一遍地做同样的事情时突然中断。非常感谢任何帮助/见解/解释者。

public class TestApp7 {

static final boolean    zipped = true;
static File             theFile = null;

private static void writeZipData() throws Exception {
    FileOutputStream fos = new FileOutputStream(theFile);
    BufferedOutputStream bos = null;
    if (zipped) {
        GZIPOutputStream gzout = new GZIPOutputStream(fos);
        bos = new BufferedOutputStream(gzout);
    } else 
        bos = new BufferedOutputStream(fos);
    byte[] bs9 = RHUtilities.toByteArray((int)90000);
    for (int i=0; i<128000; i++)
        bos.write(bs9);
    bos.flush();
    bos.close();
}

private static void readZipData() throws Exception {
    byte[] buf = new byte[1024];
    int chunkCounter = 0;
    int intCounter = 0;
    FileInputStream fin = new FileInputStream(theFile);
    int rdLen = 0;
    if (zipped) {
        GZIPInputStream gin = new GZIPInputStream(fin);
        while ((rdLen = gin.read(buf)) != -1) {
            System.out.println("Counters: " + chunkCounter + " " + intCounter);
            for (int i=0; i<rdLen/4; i++) {
                byte[] bs = Arrays.copyOfRange(buf,(i*4),((i+1)*4));
                intCounter++;
                System.out.print(bs[0] + " " + bs[1] + " " + bs[2] + " " + bs[3]);
            }
            chunkCounter++;
        }
        gin.close();
    } else {
        while ((rdLen = fin.read(buf)) != -1) {
            System.out.println("Counters: " + chunkCounter + " " + intCounter);
            for (int i=0; i<rdLen/4; i++) {
                byte[] bs = Arrays.copyOfRange(buf,(i*4),((i+1)*4));
                intCounter++;
                System.out.print(bs[0] + " " + bs[1] + " " + bs[2] + " " + bs[3]);
            }
            chunkCounter++;
        }
    }
    fin.close();
}

public static void main(String args[]) {
    try {
        if (zipped)
            theFile = new File("Test.gz");
        else
            theFile = new File("Test.dat");
        writeZipData();
        readZipData();
    } catch (Throwable e) { e.printStackTrace(); }
}
}

【问题讨论】:

  • 使用rdLen 的循环假定它始终是 4 的倍数。在我看来,这似乎是一个危险的假设。
  • 我明白。我在这里这样做是为了显示我遇到的问题。这种情况下的代码只写出和读入 4 字节整数。
  • 这并不意味着对read 的调用总是会返回4 个字节的倍数。如果幸运的话,也许会,但不能保证。
  • TX 乔恩。也许我误解了内部运作。我对文档的阅读说 GZIPInputStream.read 用流中的下一个 1024 字节填充提供的 1024 字节缓冲区(然后我将 Arrays.copyOfRange 分成 4 字节块并强制转换为整数)。你是说 GZIPInputStream.read 可能只填充部分提供的缓冲区?
  • 是的,就像其他InputStream一样。 GZipInputStream.read 文档:“如果 len 不为零,则该方法将阻塞,直到可以解压缩 some 输入”(强调我的)。您应该永远假设流读取了您要求的所有数据...我通常对此提出的一个例外是ByteArrayInputStream,并且我知道有足够的数据可以填充缓冲区。我并不是说 这里的问题,但您的代码肯定做出了不恰当的假设。

标签: java gzipinputstream


【解决方案1】:

因此,基于 Jon 出色的 cmets ... 即使流中有更多字节,您也不能依赖 .read(buffer) 填充缓冲区 - 它停在 BufferedOutputStream 包装的 GZIPOutputStream 保存一大块数据的边界处.只需添加另一个读取以超出边界并完成块

        while ((rdLen = gin.read(buf)) != -1) {
            if (rdLen<chunksize) {
                byte[] missBytes = new byte[chunksize-rdLen];
                int rdLine_miss = 0;
                if ((rdLine_miss = gin.read(missBytes)) > 0)
                    System.arraycopy(missBytes,0,buf,rdLen,rdLine_miss);
                rdLen += rdLine_miss;
            }
            for (int i=0; i<rdLen/4; i++) {
                byte[] bs = Arrays.copyOfRange(buf,(i*4),((i+1)*4));
                intCounter++;
                System.out.println(bs[0] + " " + bs[1] + " " + bs[2] + " " + bs[3] + " ");
            }
            chunkCounter++;
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-06
    • 2012-09-01
    • 2012-02-02
    • 2013-10-23
    相关资源
    最近更新 更多