2016-11-30 122 views
4

调试Python的zlib和golang的zlib之间的区别。以下为什么不具有相同的结果?golang/python zlib区别

compress.go

package main 

import (
    "compress/flate" 
    "bytes" 
    "fmt" 
) 


func compress(source string) []byte { 
    w, _ := flate.NewWriter(nil, 7) 
    buf := new(bytes.Buffer) 

    w.Reset(buf) 
    w.Write([]byte(source)) 
    w.Close() 

    return buf.Bytes() 
} 


func main() { 
    example := "foo" 
    compressed := compress(example) 
    fmt.Println(compressed) 
} 

compress.py

from __future__ import print_function 

import zlib 


def compress(source): 
    # golang zlib strips header + checksum 
    compressor = zlib.compressobj(7, zlib.DEFLATED, -15) 
    compressor.compress(source) 
    # python zlib defaults to Z_FLUSH, but 
    # https://golang.org/pkg/compress/flate/#Writer.Flush 
    # says "Flush is equivalent to Z_SYNC_FLUSH" 
    return compressor.flush(zlib.Z_SYNC_FLUSH) 


def main(): 
    example = u"foo" 
    compressed = compress(example) 
    print(list(bytearray(compressed))) 


if __name__ == "__main__": 
    main() 

结果

$ go version 
go version go1.7.3 darwin/amd64 
$ go build compress.go 
$ ./compress 
[74 203 207 7 4 0 0 255 255] 
$ python --version 
$ python 2.7.12 
$ python compress.py 
[74, 203, 207, 7, 0, 0, 0, 255, 255] 

Python的版本有0第五个字节,但golang版本有4 - 是什么导致不同的输出?

+0

zlib使用DEFLATE实现,但flate和zlib不一样。在这里,你正在关闭flate流,而在python中,你只是在冲洗。如果将Go代码更改为'Flush()',则输出将相同。还要注意不同的实现不能保证产生相同的二进制输出,它们只能保证产生兼容的输出。 – JimB

+0

@ jimb:https://golang.org/pkg/compress/flate/说:“Package flate实现了RFC 1951中描述的DEFLATE压缩数据格式...”,这似乎与第一句相矛盾,或者我误解了你(或docs =))。同样,https://golang.org/pkg/compress/flate/#Writer.Close声明刷新作者并在'w.Write(...)'行添加一个明确的'w.Flush()'后添加更多的填充/校验和字节。你介意提供一些更详细的信息,因为我明显没有遵循这些内容。 – everial

+1

该输出与python输出相匹配:https://play.golang.org/p/_SCAspI3Mq。我不明白你发现什么矛盾;你在python中使用zlib,它在内部使用DEFLATE来产生一个zlib格式的输出,而你的Go例子直接使用DEFLATE实现。我不知道是否可以让python zlib库输出原始完整的DEFLATE流,但是试图让不同的库输出压缩数据的逐字节匹配似乎不是有用或可维护的。 – JimB

回答

1

python示例的输出不是一个“完整”流,它只是在压缩第一个字符串之后刷新缓冲区。您可以通过使用Flush()更换Close()得到的Go代码输出相同:

https://play.golang.org/p/BMcjTln-ej

func compress(source string) []byte { 
    buf := new(bytes.Buffer) 
    w, _ := flate.NewWriter(buf, 7) 
    w.Write([]byte(source)) 
    w.Flush() 

    return buf.Bytes() 
} 

但是,你比较从zlib的Python中,它使用内部DEFLATE产生的zlib格式输出输出,和flate在Go中,其中的DEFLATE实现。我不知道是否可以让python zlib库输出原始完整的DEFLATE流,但是试图让不同的库输出压缩数据的逐字节匹配似乎不是有用或可维护的。压缩库的输出只能保证兼容,不完全相同。

+0

哎呀,对不起,我花了这么长时间才接受答案,错过了通知。感谢您将它写得很好。 =) – everial