Python中的zlib.compress和Java(Android)的Deflater.deflate兼容吗?

6 投票
3 回答
3977 浏览
提问于 2025-04-15 20:18

我正在把一个Python应用程序移植到Android上,这个应用程序需要和一个网络服务进行通信,发送压缩的数据。

为此,它使用了下面的方法:

def stuff(self, data):
    "Convert into UTF-8 and compress."
    return zlib.compress(simplejson.dumps(data))

我在Android上尝试用下面的方法来模拟这个行为:

private String compressString(String stringToCompress)
{
    Log.i(TAG, "Compressing String " + stringToCompress);
    byte[] input = stringToCompress.getBytes(); 
    // Create the compressor with highest level of compression 
    Deflater compressor = new Deflater(); 
    //compressor.setLevel(Deflater.BEST_COMPRESSION); 
    // Give the compressor the data to compress 
    compressor.setInput(input); 
    compressor.finish(); 
    // Create an expandable byte array to hold the compressed data. 
    // You cannot use an array that's the same size as the orginal because 
    // there is no guarantee that the compressed data will be smaller than 
    // the uncompressed data. 
    ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length); 
    // Compress the data 
    byte[] buf = new byte[1024]; 
    while (!compressor.finished()) 
    { 
        int count = compressor.deflate(buf); 
        bos.write(buf, 0, count); 
    } 

    try { 
        bos.close(); 
    } catch (IOException e) 
    { 

    } 
    // Get the compressed data 
    byte[] compressedData = bos.toByteArray(); 

    Log.i(TAG, "Finished to compress string " + stringToCompress);

    return new String(compressedData);
}

但是从服务器返回的HTTP响应不正确,我猜是因为Java中的压缩结果和Python中的不一样。

我做了一个小测试,分别用zlib.compress和deflate压缩了字符"a"。

在Python中,zlib.compress()的结果是:x%9CSJT%02%00%01M%00%A6

而在Android中,Deflater.deflate的结果是:H%EF%BF%BDK%04%00%00b%00b

我应该如何在Android中压缩数据,才能得到和Python中zlib.compress()一样的结果呢?

任何帮助、指导或建议都非常感谢!

3 个回答

0

这行代码 byte[] input = stringToCompress.getBytes("utf-8"); 有帮助吗?如果你的系统默认的编码不是UTF-8,这行代码会强制把字符串转换成字节时使用UTF-8编码。同样,在你代码的最后一行创建 new String 的时候,你也可能需要明确指定使用UTF-8作为解码的字符集。

7

compress和deflate是两种不同的压缩算法,所以它们是不兼容的。举个例子,下面是用这两种算法压缩字母'a'的结果,使用的是Tcl语言:

% binary encode hex [zlib compress a]
789c4b040000620062
% binary encode hex [zlib deflate a]
4b0400

你的Python代码确实是在使用compress算法。而安卓的代码是在使用deflate算法。不过,你的安卓版本前面还多了一个UTF-8字节顺序标记(\xef\xbf\xbf)。

你可以用Python生成deflate格式的数据:

def deflate(data):
    zobj = zlib.compressobj(6,zlib.DEFLATED,-zlib.MAX_WBITS,zlib.DEF_MEM_LEVEL,0)
    zdata = zobj.compress(data)
    zdata += zobj.flush()
    return zdata
>>> deflate("a")
'K\x04\x00'
2

虽然这两种算法不完全相同,但它们似乎是完全兼容的(也就是说,如果你用Deflater.deflate压缩一个字符串,你可以用zlib正确地解压缩它)。

我遇到的问题是,所有在POST请求中的表单变量都需要进行百分比编码,而我的安卓应用没有做到这一点。在发送数据之前先把它编码成Base64,然后修改服务器在解压缩之前用Base64解码,这样就解决了问题。

撰写回答