为什么我的 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);
我正在尝试对一些数据进行 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);