Swift 和 Go 之间的 Zlib 压缩
Zlib compression between Swift and Go
我的 Swift 应用程序与用 Go 编写的服务器通信。我想使用 Zlib 压缩传输的数据,但压缩结果似乎与 Swift 和 Go 不同。
这里是 Go
版本:
sourceString := "A-t-elle besoin d'autres preuves ? Acceptez-la pour le plaisir. J'ai tant fait que de la cueillir, Et c'est presque une fleur-des-veuves."
// Compression
var b bytes.Buffer
writer := zlib.NewWriter(&b)
writer.Write([]byte(sourceString))
writer.Close()
// Base 64
b64 := base64.StdEncoding.EncodeToString(b.Bytes())
fmt.Println(b64)
它给出以下 (Go Playground):
eJwczb2tg0AQReFWbkbylhaeCJy4i/FykUYaLev5IXD1Fs6Pzre1bDQjXoxTB/ZFKp2B6ayLgX9svXMmP80E8yyHEdNEQ33FcxFFykgcool3ETthgl5UM/U/PBJ9YeS9jDuoQRzG8rYz2vVz1m8AAAD//++yMFQ=
现在使用以下 Swift
代码 (based on this article):
let sourceString = "A-t-elle besoin d'autres preuves ? Acceptez-la pour le plaisir. J'ai tant fait que de la cueillir, Et c'est presque une fleur-des-veuves."
var sourceBuffer = Array(sourceString.utf8)
let destinationBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: sourceString.count)
let algorithm = COMPRESSION_ZLIB
let compressedSize = compression_encode_buffer(destinationBuffer, sourceString.count, &sourceBuffer, sourceString.count, nil, algorithm)
if compressedSize == 0 {
fatalError("Encoding failed.")
}
// EDIT after @Steffen Ullrich answer
// let encodedString = String(cString: destinationBuffer)
// let encodedStringb64 = Data(encodedString.utf8).base64EncodedString()
let encodedData = NSData(bytesNoCopy: destinationBuffer, length: compressedSize)
let encodedStringb64 = encodedData.base64EncodedString()
print(encodedStringb64)
我们得到:
H̶e̶+̶/̶v̶T̶E̶O̶7̶7̶+̶9̶M̶A̶x̶D̶0̶a̶t̶w̶7̶7̶+̶9̶U̶u̶+̶/̶v̶Q̶p̶F̶7̶7̶+̶9̶L̶O̶+̶/̶v̶e̶+̶/̶v̶e̶+̶/̶v̶T̶D̶v̶v̶7̶0̶=̶
Hc0xDsMwDEPRq3DzUucKRYYsvYXqMIAAwXFtKUNPX6cTlwf+NXumGfHmOLViTxLeOdA645r7xFoKm/ObTdDO6Ji6mejQvuCVROFSHYeo4xPETkxZgmqm/YHNURKH35fjBlGJwxg97xz5+neWHw==
如您所见,它非常不同,我在这里做错了什么?
我不熟悉 Swift 但 Go 代码 return 是一个 zlib (RFC 1950) 压缩字符串,而根据 Apple 的文档 Swift 代码最多应该return 压缩字符串 (RFC 1951),即像 zlib 压缩但没有 2 字节 zlib header。
有了这些知识,可以正确解压缩从 Go 代码中提取的 return 字符串,而从 Swift 中提取的字符串 return 则不能。大小上的差异也很明显,这让我假设某些东西被切断了。看起来您将压缩数据 destinationBuffer
视为 cString
,这意味着字符串中的任何 [=12=]
字节都将被视为字符串的结尾。这样的 [=12=]
字节很可能是压缩的结果,并且字符串在那里被截断,即您的输出仅显示真实 destinationBuffer
的一部分。 (编辑:最后一部分不再适用,因为 OP 以正确的结果更改了问题)。
我的 Swift 应用程序与用 Go 编写的服务器通信。我想使用 Zlib 压缩传输的数据,但压缩结果似乎与 Swift 和 Go 不同。
这里是 Go
版本:
sourceString := "A-t-elle besoin d'autres preuves ? Acceptez-la pour le plaisir. J'ai tant fait que de la cueillir, Et c'est presque une fleur-des-veuves."
// Compression
var b bytes.Buffer
writer := zlib.NewWriter(&b)
writer.Write([]byte(sourceString))
writer.Close()
// Base 64
b64 := base64.StdEncoding.EncodeToString(b.Bytes())
fmt.Println(b64)
它给出以下 (Go Playground):
eJwczb2tg0AQReFWbkbylhaeCJy4i/FykUYaLev5IXD1Fs6Pzre1bDQjXoxTB/ZFKp2B6ayLgX9svXMmP80E8yyHEdNEQ33FcxFFykgcool3ETthgl5UM/U/PBJ9YeS9jDuoQRzG8rYz2vVz1m8AAAD//++yMFQ=
现在使用以下 Swift
代码 (based on this article):
let sourceString = "A-t-elle besoin d'autres preuves ? Acceptez-la pour le plaisir. J'ai tant fait que de la cueillir, Et c'est presque une fleur-des-veuves."
var sourceBuffer = Array(sourceString.utf8)
let destinationBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: sourceString.count)
let algorithm = COMPRESSION_ZLIB
let compressedSize = compression_encode_buffer(destinationBuffer, sourceString.count, &sourceBuffer, sourceString.count, nil, algorithm)
if compressedSize == 0 {
fatalError("Encoding failed.")
}
// EDIT after @Steffen Ullrich answer
// let encodedString = String(cString: destinationBuffer)
// let encodedStringb64 = Data(encodedString.utf8).base64EncodedString()
let encodedData = NSData(bytesNoCopy: destinationBuffer, length: compressedSize)
let encodedStringb64 = encodedData.base64EncodedString()
print(encodedStringb64)
我们得到:
H̶e̶+̶/̶v̶T̶E̶O̶7̶7̶+̶9̶M̶A̶x̶D̶0̶a̶t̶w̶7̶7̶+̶9̶U̶u̶+̶/̶v̶Q̶p̶F̶7̶7̶+̶9̶L̶O̶+̶/̶v̶e̶+̶/̶v̶e̶+̶/̶v̶T̶D̶v̶v̶7̶0̶=̶ Hc0xDsMwDEPRq3DzUucKRYYsvYXqMIAAwXFtKUNPX6cTlwf+NXumGfHmOLViTxLeOdA645r7xFoKm/ObTdDO6Ji6mejQvuCVROFSHYeo4xPETkxZgmqm/YHNURKH35fjBlGJwxg97xz5+neWHw==
如您所见,它非常不同,我在这里做错了什么?
我不熟悉 Swift 但 Go 代码 return 是一个 zlib (RFC 1950) 压缩字符串,而根据 Apple 的文档 Swift 代码最多应该return 压缩字符串 (RFC 1951),即像 zlib 压缩但没有 2 字节 zlib header。
有了这些知识,可以正确解压缩从 Go 代码中提取的 return 字符串,而从 Swift 中提取的字符串 return 则不能。大小上的差异也很明显,这让我假设某些东西被切断了。看起来您将压缩数据 destinationBuffer
视为 cString
,这意味着字符串中的任何 [=12=]
字节都将被视为字符串的结尾。这样的 [=12=]
字节很可能是压缩的结果,并且字符串在那里被截断,即您的输出仅显示真实 destinationBuffer
的一部分。 (编辑:最后一部分不再适用,因为 OP 以正确的结果更改了问题)。