解压缩文件大小错误

时间:2016-08-30 09:38:08

标签: c# .net

我有一个解压缩* .gz文件的方法:

using (FileStream originalFileStream = new FileStream(gztempfilename, FileMode.Open, FileAccess.Read))
{
  using (FileStream decompressedFileStream = new FileStream(outputtempfilename, FileMode.Create, FileAccess.Write))
  {
    using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
    {
      decompressionStream.CopyTo(decompressedFileStream);
    }
  }
}

它工作得很好,但最近我收到了大小错误的文件包: 当我用7-zip打开它们时,它们的包装尺寸 ~1,600,000和尺寸 = 7(它应该是~20,000,000)。 enter image description here 因此,当我使用此代码提取它时,我只获得文件的一部分。但是当我使用7-zip解压缩此文件时,我会收到完整的文件。

如何在我的代码中处理这种情况?

5 个答案:

答案 0 :(得分:2)

我的猜测是,当GZipping文件时,另一端会出错。看起来它没有正确设置ISIZE bytes

ISIZE字节是有效GZip文件的最后四个字节,它位于32位CRC值之后,而后者又直接位于压缩数据字节之后。

7-Zip似乎可以抵御这些错误,而GZipStream则不然。然而奇怪的是,7-Zip没有向您显示任何错误。它应该显示给你(用7-Zip 16.02 x64 / Win7测试)......

  • 如果大小错误,则会出现CRC错误,
  • “意外的数据结束”,以防部分或全部ISIZE字节被切断,
  • “有效载荷数据结束后有一些数据”,以防ISIZE字节后面有更多数据。

7-Zip始终使用打包文件的最后四个字节来确定原始解压缩文件的大小,而不检查文件是否有效以及为此读取的字节是否实际上是ISIZE字节。

您可以通过使用十六进制查看器检查GZipped文件的最后四个字节来验证这一点。对于您的示例,它们应该是07 00 00 00

如果您知道解压缩的原始文件的确切大小,则可以替换这些字节,以便它们指定正确的大小。例如,如果解压缩文件的大小为 20,000,078 ,其中 01312D4E 以十六进制( 0 - 填充到八位数),那些字节应为4E 2D 31 01

如果您不知道确切的尺寸,可以尝试使用最大值替换它们,即FF FF FF FF

然后再次尝试解压缩代码。

这显然只是解决问题的一个黑客。最好尝试修复GZips您收到的文件的代码,或者尝试找到比GZipStream更强大的库。

答案 1 :(得分:1)

我使用了this库中的ICSharpCode.SharpZipLib.GZip.GZipInputStream而不是System.IO.Compression.GZipStream,它帮助了。

答案 2 :(得分:0)

您是否尝试过检查尺寸?即:

byte[] bArray;
using (FileStream f = new FileStream(tempFile, FileMode.Open))
{
   bArray= new byte[f.Length];
   f.Read(b, 0, f.Length);
}

此致

尝试:

            GZipStream uncompressed = new GZipStream(streamIn, CompressionMode.Decompress, true);
            FileStream streamOut = new FileStream(tempDoc[0], FileMode.Create, FileAccess.Write, FileShare.None);

答案 3 :(得分:0)

看起来这是GZipStream中的某种错误(它不会将原始文件长度写入文件的gz末尾)。 您需要更改使用GZipStream压缩文件的方式。 运作方式:

            inputBytes = Encoding.UTF8.GetBytes(output);
            using (var outputStream = new MemoryStream())
            {
                using (var gZipStream = new GZipStream(outputStream, CompressionMode.Compress))
                    gZipStream.Write(inputBytes, 0, inputBytes.Length);
                System.IO.File.WriteAllBytes("file.xml.gz", outputStream.ToArray());
            }

这种方式将导致您遇到错误(无论是否使用Flush()):

            inputBytes = Encoding.UTF8.GetBytes(output);
            using (var outputStream = new MemoryStream())
            {
                using (var gZipStream = new GZipStream(outputStream, CompressionMode.Compress))
                {
                    gZipStream.Write(inputBytes, 0, inputBytes.Length);
                    System.IO.File.WriteAllBytes("file.xml.gz", outputStream.ToArray());
                }
            }

答案 4 :(得分:0)

关闭gZip流后,您可能需要调用decompressedStream.Seek()。

shown here