Java:创建GZIPInputStream时出错:不是GZIP格式

9
我正在尝试使用以下Java代码对字符串进行压缩和解压缩。但是,将新的ByteArrayInputStream对象传递给GZipInputStream对象的那一行会引发“java.util.zip.ZipException:Not in GZIP format”异常。有谁知道如何解决这个问题吗?
        String orig = ".............";

        // compress it
        ByteArrayOutputStream baostream = new ByteArrayOutputStream();
        OutputStream outStream = new GZIPOutputStream(baostream);
        outStream.write(orig.getBytes());
        outStream.close();
        String compressedStr = baostream.toString();

        // uncompress it
        InputStream inStream = new GZIPInputStream(new ByteArrayInputStream(compressedStr.getBytes()));
        ByteArrayOutputStream baoStream2 = new ByteArrayOutputStream();
        byte[] buffer = new byte[8192];
        int len;
        while((len = inStream.read(buffer))>0)
            baoStream2.write(buffer, 0, len);
        String uncompressedStr = baoStream2.toString();
3个回答

13
混合使用字符串和字节数组;这永远不适用。并且只在相同编码的操作系统上有效。并非所有的字节数组都可以转换为字符串,而反向转换可能会给出其他字节。
压缩字节不一定要表示为字符串。
在getBytes和new String中明确设置编码。
    String orig = ".............";

    // Compress it
    ByteArrayOutputStream baostream = new ByteArrayOutputStream();
    OutputStream outStream = new GZIPOutputStream(baostream);
    outStream.write(orig.getBytes("UTF-8"));
    outStream.close();
    byte[] compressedBytes = baostream.toByteArray(); // toString not always possible

    // Uncompress it
    InputStream inStream = new GZIPInputStream(
            new ByteArrayInputStream(compressedBytes));
    ByteArrayOutputStream baoStream2 = new ByteArrayOutputStream();
    byte[] buffer = new byte[8192];
    int len;
    while ((len = inStream.read(buffer)) > 0) {
        baoStream2.write(buffer, 0, len);
    }
    String uncompressedStr = baoStream2.toString("UTF-8");

    System.out.println("orig: " + orig);
    System.out.println("unc:  " + uncompressedStr);

5
Joop似乎已经有了解决方案,但我觉得我必须补充一点: 压缩通常会产生一个二进制流,特别是GZIP。 你绝不能尝试从这个流中构造一个字符串 - 它破坏。 如果需要将其转换为纯文本表示形式,请查看Base64编码、十六进制编码,甚至简单的二进制编码。
简而言之,字符串对象适用于人类阅读的内容。字节数组(以及许多其他内容)适用于机器阅读的内容。

0

您使用默认平台编码(可能是UTF-8)将baostream编码为字符串。您应该使用baostream.getBytes()来处理二进制数据,而不是字符串。

如果您一定要使用字符串,请使用8位编码,例如baostream.toString("ISO-8859-1"),并使用相同的字符集读取它。


2
即使在两端指定字符编码,直接将字节存储到字符串中可能会变得棘手。更好的方法是使用字符串的Base64编码来处理二进制数据。Apache Commons codec提供一个非常好的类来进行Base64编码和解码 - Peter Elliott
1
同时,UTF-8绝对是一种8位编码。 - Peter Elliott
“8位编码”的口语意思是每个代码单元恰好为8位,但在ASCII之上的代码点中,UTF-8并非如此。滥用编码会间接导致术语的滥用,您提出的base64编码更好。” - Chuck Adams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接