为什么GZip算法的结果在Android和.Net中不相同?
我在android中的代码:
@H_403_8@ 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中的代码:
@H_403_8@ 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中:
@H_403_8@compressString("hello"); -> "H4sIAAAAAAAAAMtIzcnJBwCGphA2BQAAAA=="
在.Net:
@H_403_8@compressString("hello"); -> "BQAAAB+LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee++997o7nU4n99//P1xmZAFs9s5K2smeIYCqyB8/fnwfPyLmeVlW/w+GphA2BQAAAA=="
有趣的是,当我在android中使用Decompress方法解压缩.Net compressString方法的结果时,它正确返回原始字符串,但是当我解压缩android compressedString方法的结果时出错.
Android解压缩方法:
@H_403_8@ 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版本中,您应该在关闭gz后关闭bos.
另外,compressString中的这一行可能会给你带来问题:
@H_403_8@byte b[] = str.getBytes();
这将使用设备上的默认编码将字符转换为字节,这几乎肯定不是UTF-8.另一方面,.NET版本使用的是UTF8.在Android中,请尝试以下方法:
@H_403_8@byte b[] = str.getBytes("UTF-8");
编辑:在进一步查看您的代码时,我建议您像这样重写它:
@H_403_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.您需要对其进行子类化并覆盖默认压缩.最简单的方法是这样做:
@H_403_8@GZIPOutputStream gz = new GZIPOutputStream(bos) { { def.setLevel(Deflater.BEST_COMPRESSION); } };
这将重置GZIP用于提供最佳压缩的内部平减指数. (顺便说一句,如果您不熟悉它,我在这里使用的语法称为instance initializer block.)