【问题标题】:Why the result of GZip algorithm is not same in Android and .Net?为什么 GZip 算法的结果在 Android 和 .Net 中不一样?
【发布时间】:2011-08-14 04:33:45
【问题描述】:

为什么 GZip 算法在 Android 和 .Net 中的结果不一样?

我在 android 中的代码:

    public static String compressString(String str) {

    String str1 = null;
    ByteArrayOutputStream bos = null;
    try {
        bos = new ByteArrayOutputStream();
        BufferedOutputStream dest = null;

        byte b[] = str.getBytes();
        GZIPOutputStream gz = new GZIPOutputStream(bos, b.length);
        gz.write(b, 0, b.length);
        bos.close();
        gz.close();

    } catch (Exception e) {
        System.out.println(e);
        e.printStackTrace();
    }
    byte b1[] = bos.toByteArray();
    return Base64.encode(b1);
}

我在 .Net WebService 中的代码:

    public static string compressString(string text)
{
    byte[] buffer = Encoding.UTF8.GetBytes(text);
    MemoryStream ms = new MemoryStream();
    using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))
    {
        zip.Write(buffer, 0, buffer.Length);
    }

    ms.Position = 0;
    MemoryStream outStream = new MemoryStream();

    byte[] compressed = new byte[ms.Length];
    ms.Read(compressed, 0, compressed.Length);

    byte[] gzBuffer = new byte[compressed.Length + 4];
    System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
    System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
    return Convert.ToBase64String(gzBuffer);
}

在安卓中:

compressString("hello"); -> "H4sIAAAAAAAAAMtIzcnJBwCGphA2BQAAAA=="

在 .Net 中:

compressString("hello"); -> "BQAAAB+LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee++997o7nU4n99//P1xmZAFs9s5K2smeIYCqyB8/fnwfPyLmeVlW/w+GphA2BQAAAA=="

有趣的是,当我在 android 中使用 Decompress 方法解压 .Net compressString 方法的结果时,它会正确返回原始字符串,但当我执行时出现错误解压android compressedString方法的结果。

Android解压方式:

    public static String Decompress(String zipText) throws IOException {
    int size = 0;
    byte[] gzipBuff = Base64.decode(zipText);

    ByteArrayInputStream memstream = new ByteArrayInputStream(gzipBuff, 4,
            gzipBuff.length - 4);
    GZIPInputStream gzin = new GZIPInputStream(memstream);

    final int buffSize = 8192;
    byte[] tempBuffer = new byte[buffSize];
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    while ((size = gzin.read(tempBuffer, 0, buffSize)) != -1) {
        baos.write(tempBuffer, 0, size);
    }
    byte[] buffer = baos.toByteArray();
    baos.close();

    return new String(buffer, "UTF-8");
}

我认为 Android compressString 方法有错误。 有人可以帮帮我吗?

【问题讨论】:

标签: android .net gzip compression


【解决方案1】:

在Android版本中,您应该在关闭bos之后关闭gz。

另外,compressString 中的这一行可能会给您带来问题:

byte b[] = str.getBytes();

这将使用设备上的默认编码将字符转换为字节,这几乎肯定不是 UTF-8。另一方面,.NET 版本使用 UTF8。在 Android 中,试试这个:

byte b[] = str.getBytes("UTF-8");

编辑:在进一步查看您的代码时,我建议您像这样重写它:

byte b[] = str.getBytes("UTF-8");
GZIPOutputStream gz = new GZIPOutputStream(bos);
gz.write(b, 0, b.length);
gz.finish();
gz.close();
bos.close();

变化是:使用UTF-8编码字符;使用 GZIPOutputStream 的默认内部缓冲区大小;在调用bos.close() 之前调用gz.close()(后者可能甚至不需要);并在调用gz.close()之前调用gz.finish()。

编辑 2:

好吧,我应该在发生什么事之前就意识到这一点。在我看来,GZIPOutputStream 类是一个愚蠢的设计。它无法定义您想要的压缩,并且默认压缩设置为无。您需要对其进行子类化并覆盖默认压缩。最简单的方法是这样做:

GZIPOutputStream gz = new GZIPOutputStream(bos) {
    {
        def.setLevel(Deflater.BEST_COMPRESSION);
    }
};

这将重置 GZIP 用于提供最佳压缩的内部缩减程序。 (顺便说一句,如果你不熟悉它,我在这里使用的语法称为instance initializer block。)

【讨论】:

  • 我测试了您的解决方案,不幸的是它没有效率。没有任何改变。
  • 我又测试了一遍。没有改变。我再次收到“H4sIAAAAAAAAAAMtIzcnJBwCGphA2BQAAAA==”
  • 我之前测试过。没有显着变化。
【解决方案2】:

根据this answer,我有4个方法。 Android 和 .net 压缩和解压缩方法。除一种情况外,这些方法彼此兼容。

【讨论】:

    【解决方案3】:

    主要区别在于您的 .NET 代码将压缩数据的长度放入二进制数据的前四个字节中。您的 Java 代码不会这样做。它缺少长度字段。

    当您解压缩它时,您希望前四个字节的长度并在位置 4 开始 GZIP 解压缩(跳过前四个字节)。

    【讨论】:

    • .Net 在其 Base64 字符串的开头有 4 个额外字符
    • 是的,这就是我要说的。除了 GZIP 压缩数据之外,您的最终数据(在 Base 64 编码之前)有四个字节,其中包含 GZIP 压缩数据的长度。 Android压缩代码没有,Android解压代码需要它。
    • 我该如何解决?你能给我一个示例代码来解决它吗?谢谢,
    • b1(Android)的长度是25,而compressed(.Net)的长度是123。这两个字节数组的长度相差太大了。
    • 是否需要开头的四个字节(包含长度)?基于此,我可以告诉你如何解决它。
    猜你喜欢
    • 2015-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-24
    • 1970-01-01
    • 1970-01-01
    • 2012-09-03
    相关资源
    最近更新 更多