使用GZipStream在C#中压缩空输入会导致无效的gz文件

9
我正在使用C#的GZipStream类来压缩一些输入数据,但问题是当输入为空时,它会创建一个0字节的文件。在这种情况下,如果我尝试使用7zip来解压缩生成的.gz文件,它会报错并提示格式无效。如果我的输入不为空,那么它就可以正常工作。请告诉我如何创建一个有效的.gz文件,以便解压缩成一个0字节的文件?
var file = new FileStream("foo.txt.gz", FileMode.Create, FileAccess.ReadWrite);
var gzip = new GZipStream(file, CompressionMode.Compress);
var writer = new StreamWriter(gzip);

for (string line in input) {
    writer.Write(line);
}

writer.Close();
gzip.Close();
file.Close();

在上面的代码中,如果我的“input”数组为空,则最终会写入一个名为foo.txt.gz的0字节文件,并且7zip会提示该文件无效。但是如果我有一个非空数组,则可以获得有效的文件。请告诉我如何修改我的代码以解决这个问题,即使输入为空也能得到有效的.gz文件。谢谢!
编辑:这可能是.NET中的一个错误。如果您注意到相同的问题并同意这是一个错误,请在以下链接上投票: https://connect.microsoft.com/VisualStudio/feedback/details/888912/gzipstream-creates-invalid-gz-files-when-input-is-empty

4
这个Connect的bug已经不存在了...我也找不到其他关于这个问题的参考资料。 - oatsoda
2个回答

4

不幸的是,这似乎是.NET库中GZipStream实现的一个错误。

根据MSDN文档(http://msdn.microsoft.com/en-ca/library/as1ff51s.aspx),它应该"显示为一个有效的、空的压缩文件"。但是,当我测试您的代码和一些变化时,我也得到了一个完全空的文件。

相比之下,如果我使用Cygwin创建一个空的gzip文件(echo -n | gzip -9 > empty.gz),我会得到一个20字节的文件。

我想你可以通过检测输入是否为空并手动编写一个空的GZIP文件来解决这个问题。你可以参考GZIP文件文档(维基百科是一个好的起点)手动创建文件,或者在程序中硬编码需要一个空文件的20个字节(使用这种解决方案,内部时间戳和其他一些标志可能是错误的,但在实践中可能不会影响你)。

另外,使用第三方压缩库,如SharpZipLib(http://icsharpcode.github.io/SharpZipLib/)或DotNetZip(http://dotnetzip.codeplex.com/),实现GZIP并使用它们的实现代替GZipStream。


我在微软公司添加了一个错误报告,请投票支持:https://connect.microsoft.com/VisualStudio/feedback/details/888912/gzipstream-creates-invalid-gz-files-when-input-is-empty - Gadzair

1

我知道这是一个老问题,但如果你意识到你的输入流是空的,在处理GZipStream类之前,你可以进行一次空写入,它将按预期保存20个字节到输出流中,从而创建一个有效的gz文件。

你可以使用以下代码片段:

gs.Write(Array.Empty<byte>(), 0, 0);

@MarkAdler 我添加的代码片段实际上解决了这个问题。如果你只是创建一个 GZipStream 然后立即保存它,你最终会得到一个 0 字节的 .gz 文件,这是无效的。如果你进行任何写操作,GZipStream 将创建 GZip 头结构。因此,当添加了我展示的 0 字节写入时,保存的 .gz 文件将具有基本的 gz 流,可以按预期解压缩为 0 字节文件,而在写入流中任何其他内容的情况下也不会产生任何副作用。 - Artiom Chilaru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接