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

为什么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,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,buffer.Length);
    }

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

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

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

在android中:

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,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,buffSize)) != -1) {
        baos.write(tempBuffer,size);
    }
    byte[] buffer = baos.toByteArray();
    baos.close();

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

我认为Android compressstring方法中存在错误.
有谁能够帮我?

最佳答案
在Android版本中,您应该在关闭gz后关闭bos.

另外,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,b.length);
gz.finish();
gz.close();
bos.close();

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

编辑2:

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

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

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

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...