为什么我的 GZip 实现会导致无效的 gzip

Why does my GZip implementation result in invalid gzip

我正在尝试对一些数据进行 gzip 压缩,这些数据将由一个单独的应用程序(一个名为 Tiled 的 tilemap 程序)使用。我无法生成应用程序可以理解的数据,我相信这是因为我的压缩数据无效。为了验证,我已经在 https://codebeautify.org/gzip-decompress-online 上测试了我的压缩 base64 字符串,根据这个网站,我的 gzip 字符串也是无效的。

我的实现是:

uint[] values = new uint[4];
values[0] = 1;
values[1] = 1;
values[2] = 1;
values[3] = 1;

using var memoryStream = new MemoryStream();
using var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress);
using var writer = new BinaryWriter(gzipStream);
for (int i = 0; i < values.Length; i++)
{
    writer.Write(values[i]);
}

writer.Flush();
gzipStream.Flush();
memoryStream.Position = 0;
var memoryBytes = memoryStream.ToArray();

var convertedString = Convert.ToBase64String(memoryBytes);

我得到的字符串是:

H4sIAAAAAAAACmJkYGBgRMIAAAAA//8=

在上面列出的 GZip 网站中输入时,returns“数据完整性错误”

但是,如果我尝试在 C# 中解压缩它,我会得到相同的数据,因此“往返”有效。

作为参考,通过 Tiled 压缩的相同数据 (1, 1, 1, 1) 会生成此字符串:

H4sIAAAAAAAACmNkYGBgRMIAUPFgrRAAAAA=

该字符串在上面列出的网站中也能正确解压。请注意,两个字符串都使用 C# 中的 GZipStream 正确解压缩,因此 .NET 中的 GZip 实现必须以某种方式更能容忍我做错的任何事情。

谁能告诉我为什么我的输出字符串与 Tiled 生成的字符串不匹配,为什么我的字符串根据 Tiled 和那个应用程序无效,以及如何解决这个问题?

Flush() 强制压缩目前提供的数据,但不会完成 gzip 流。您需要使用 Close().

第一个是不完整的 gzip 流,它在 deflate 流的中间结束并且没有 gzip 尾部。第二个是一个完整的 gzip 流,带有一个终止的 deflate 流,后跟一个带有 CRC 和长度的 gzip 尾部,用于检查未压缩的数据。

正如 Mark 提到的,您需要使用 Close() 来完成 gzip 流。此外,您不需要刷新写入器或重置 memoryStream 位置。这将通过关闭 GzipStream 实例来处理。

uint[] values = new uint[4];
values[0] = 1;
values[1] = 1;
values[2] = 1;
values[3] = 1;

using var memoryStream = new MemoryStream();
using var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress);
using var writer = new BinaryWriter(gzipStream);
for (int i = 0; i < values.Length; i++)
{
    writer.Write(values[i]);
}

gzipStream.Close();

var memoryBytes = memoryStream.ToArray();
var convertedString = Convert.ToBase64String(memoryBytes);