【问题标题】:Android: uncompress concatenated gzip-compressed filesAndroid:解压缩连接的 gzip 压缩文件
【发布时间】:2015-02-25 09:01:50
【问题描述】:

gzipdocumented 支持压缩文件的拼接:

$ echo hello >hhh
$ echo world >www
$ cat hhh www
hello
world
$ echo hello | gzip >hhhh
$ echo world | gzip >wwww
$ cat hhhh wwww | gunzip
hello
world

我可以使用GZIPOutputStream 创建一个连接文件,但不幸的是GZIPInputStream 只读取数据的第一部分(从命令行运行的gunzip 读取所有数据。)

我在 Android 4.1.2 和 4.4.2 上都看到了这一点。

如何从 Java 中读取整个文件?

更新:
演示错误的示例(主机版本):

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;


class GZTest {
    static void append(File f, String s) {
        try {
            FileOutputStream fos = new FileOutputStream(f, true);
            //FileOutputStream gzos = fos;
            GZIPOutputStream gzos = new GZIPOutputStream(fos);
            gzos.write(s.getBytes("UTF-8"));
            gzos.close(); // TODO: do it finally{}
            fos.close(); // TODO: do it finally{}
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    static String readAll(File f) {
        try {
            FileInputStream fis = new FileInputStream(f);
            //FileInputStream gzis = fis;
            GZIPInputStream gzis = new GZIPInputStream(fis);
            byte[] buf = new byte[4096];
            int len = gzis.read(buf);
            gzis.close(); // TODO: do it finally{}
            fis.close(); // TODO: do it finally{}
            return new String(Arrays.copyOf(buf, len), "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}

public class A {
    public static void main(String[] args) {
        System.out.println("~~~");
        File f = new File("x.y");
        f.delete();
        GZTest.append(f, "Hello, ");
        GZTest.append(f, "world!\n");
        System.out.println(GZTest.readAll(f));
    }
}

运行它:

$ javac A.java
$ java A
~~~
Hello, 
$ gunzip <x.y
Hello, world!

更新2
看起来这是错误 JDK-2192186,据报道已于 2010-08-03 修复。然而,这个错误现在就在这里。

【问题讨论】:

  • 你试过在第一个完成后创建第二个“GZIPInputStream”吗?
  • 顺便看看这个:*.com/questions/13749891/…
  • 是的...顺便说一句,我在主机上看到与java version "1.8.0_31" 相同的错误 错误报告提供了一种解决方法,但代码很糟糕。 Oracle 是否发布了应用了修复的代码?

标签: java android gzip


【解决方案1】:

对于宿主java,正确的读法是:

static String readAll(File f) {
    try {
        FileInputStream fis = new FileInputStream(f);
        //FileInputStream gzis = fis;
        GZIPInputStream gzis = new GZIPInputStream(fis);
        final int SIZE=4096;
        byte[] buf = new byte[SIZE];
        int len=0, read=0;
        do {
            read = gzis.read(buf, len, SIZE-len);
            if (read < 0) {
                break;
            }
            len += read;
        } while (len<SIZE);
        gzis.close(); // TODO: do it finally{}
        return new String(Arrays.copyOf(buf, len), "UTF-8");
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

(这个 readAll() 将用于代替问题中的 readAll()

此代码在 Android 上不起作用!!!

在 Android 上,这仍然给出了

D/~~~     (30098): Hello, 

而命令行 gunzip 说

# cat /data/data/com.example.gzctest2/files/x.y | gunzip
Hello, world!

【讨论】:

    【解决方案2】:

    刚刚尝试了truncated output from GZIPInputStream on Android 的解决方案:它有效。 要克隆带有修复程序 https://github.com/ymnk/jzlib/tree/concatenated_gzip_streams 的分支,请使用:

    git clone https://github.com/ymnk/jzlib.git
    git checkout concatenated_gzip_streams
    

    然后将目录src/main/java(不能只复制一个文件)复制到你的项目中并替换导入:

    //import java.util.zip.GZIPInputStream;
    import com.jcraft.jzlib.GZIPInputStream;
    

    它适用于 Android!

    如果您想删除不需要的文件,需要: Adler32.java Deflate.java GZIPInputStream.java Inflate.java InfTree.java Tree.java Checksum.java GZIPException.java InfBlocks.java InflaterInputStream.java JZlib.java ZStream.java CRC32.java GZIPHeader.java InfCodes.java Inflater.java StaticTree.java
    并且不会需要: Deflater.java DeflaterOutputStream.java GZIPOutputStream.java ZInputStream.java ZOutputStream.java ZStreamException.java

    看起来删除 6 个未使用的文件 (24K) 而留下 17 个文件 (198K) 是不值得的结果。

    【讨论】:

      最近更新 更多