Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# GZipStream在大文件上悄悄失败,流以2GB结束_C#_.net_Gzipstream - Fatal编程技术网

C# GZipStream在大文件上悄悄失败,流以2GB结束

C# GZipStream在大文件上悄悄失败,流以2GB结束,c#,.net,gzipstream,C#,.net,Gzipstream,我在使用GZipStream解压(30GB压缩文本,480GB未压缩)流过早结束时遇到问题。没有引发异常,只是gz.Read()开始返回零: using(var gz = new GZipStream(File.Open("freebase-rdf-latest.gz", FileMode.Open), CompressionMode.Decompress)) { var buffer = new byte[1048576]; int read, total = 0; w

我在使用
GZipStream
解压(30GB压缩文本,480GB未压缩)流过早结束时遇到问题。没有引发异常,只是
gz.Read()
开始返回零:

using(var gz = new GZipStream(File.Open("freebase-rdf-latest.gz", FileMode.Open), CompressionMode.Decompress))
{
    var buffer = new byte[1048576];
    int read, total = 0;
    while ((read = gz.Read(buffer, 0, buffer.Length)) > 0)
        total += read;

    // total is 1945715682 here
    // subsequent reads return 0
}
该文件可以与其他应用程序一起解压(我尝试了gzip和7zip)

四处嗅探,我在以前版本的

GZipStream类可能无法解压缩导致错误的数据 在超过8 GB的未压缩数据中

该注释已在最新版本的文档中删除。我使用的是.NET4.5.2,对我来说,流在解压缩了不到2GB后就结束了

有人更了解这个限制吗?文档中的语言暗示了其他的先决条件,而不仅仅是解包超过8gb的文件——我相当确定我过去使用过GZipStream来处理非常大的文件,而没有碰到这个问题

还有,有谁能推荐一个替代GZipStream的drop-in,我可以用它代替System.IO.Compression吗

更新

我尝试用Ionic.Zlib(DotNetZip)替换System.IO.Compression,得到了相同的结果

我尝试了ICSharpCode.SharpZipLib的GZipInputStream,第一次读取时就得到了“未知块类型6”

我尝试了SevenZipSharp,但是没有用于读取的流装饰器-只有各种阻塞“提取”方法来解压整个流,这不是我想要的

另一次更新

下面的代码使用zlib1.dll正确解压整个文件。它也可以在GZipStream的四分之一时间内完成

var gzFile = gzopen("freebase-rdf-latest.gz", "rb");

var buffer = new byte[1048576];
int read, total = 0;
while ((read = gzread(gzFile, buffer, buffer.Length)) > 0)
    total += read;

[DllImport("zlib1")] IntPtr gzopen(string path, string mode);
[DllImport("zlib1")] int gzread(IntPtr gzFile, byte[] buf, int len);
[DllImport("zlib1")] int gzclose(IntPtr gzFile);

…因此,显然.NET中所有现有的GZip库都存在与zlib的兼容性问题。我使用的zlib1.dll来自我的mingw64目录(我的机器上大约有十几个zlib1.dll,但这是唯一的64位)。对于大文件,您不应该使用流读取器:

        var buffer = new byte[1024 * 1024];
        using (var gz = new GZipStream(new FileStream("freebase-rdf-latest.gz", FileMode.Open), CompressionMode.Decompress))            
        {
            var bytesRead = 0;
            while (bytesRead < buffer.Length)
            {
                bytesRead = gz.Read(buffer, 0, buffer.Length);
                Console.WriteLine(bytesRead);
            }
        }
var buffer=新字节[1024*1024];
使用(var gz=new GZipStream(new FileStream(“freebase rdf latest.gz”,FileMode.Open),CompressionMode.Decompress))
{
var bytesRead=0;
while(字节读取<缓冲区长度)
{
bytesRead=gz.Read(buffer,0,buffer.Length);
控制台写入线(字节读取);
}
}

我有点晚了,但我已经找到了这个问题的原因和解决方案

这个大文件不仅包含一个gzip流,而且正好包含200个流。(每个gzip流的压缩大小:150-155MB)

第一个“gzip文件”使用可选的额外字段来描述所有压缩的gzip流的长度。许多解压器不支持这种流式风格,只解码第一个条目。(150 MB->2 GB)

1.:readheader方法:(抱歉,如果看起来像黑客风格:-)

需要一些时间(30-40分钟),但它可以工作!(无外部LIB)

速度:解压数据速率约为200 MB/s


如果没有什么改动,应该可以使用多线程。

我不知道,但是当我将StreamReader与GZipStream一起使用时,我会遇到问题。如果没有StreamReader,问题是可以重现的。编译时您是x86还是x64?你也可以看看吗?它在引擎盖下使用zlib。不过,我不确定DeflateStream是否适用于您正在使用的内容。@AdamSears x64但我尝试了32位,但没有任何区别。我刚采用了zlib,就从这个角度出发了,但我很高兴有人终于揭开了谜底,谢谢!谢谢,这让我开始发疯了。相同的文件,不同的语言(Ruby),相同的问题。如果有人偶然发现了它并使用了UNIX,可以通过将
gzipreder.open(file){code>更改为
IO.popen([“/usr/bin/gzcat”,file]){f |…}
来解决。
static long[] ReadGzipLengths(Stream stream)
{
  if (!stream.CanSeek || !stream.CanRead) return null; // can seek and read?

  int fieldBytes;
  if (stream.ReadByte() == 0x1f && stream.ReadByte() == 0x8b // gzip magic-code
      && stream.ReadByte() == 0x08 // deflate-mode
      && stream.ReadByte() == 0x04 // flagged: has extra-field
      && stream.ReadByte() + stream.ReadByte() + stream.ReadByte() + stream.ReadByte() >= 0 // unix timestamp (ignored)
      && stream.ReadByte() == 0x00 // extra-flag: sould be zero
      && stream.ReadByte() >= 0 // OS-Type (ignored)
      && (fieldBytes = stream.ReadByte() + stream.ReadByte() * 256 - 4) > 0 // length of extra-field (subtract 4 bytes field-header)
      && stream.ReadByte() == 0x53 && stream.ReadByte() == 0x5a // field-header: must be "SZ" (mean: gzip-sizes as uint32-values)
      && stream.ReadByte() + stream.ReadByte() * 256 == fieldBytes // should have same length
    )
  {
    var buf = new byte[fieldBytes];
    if (stream.Read(buf, 0, fieldBytes) == fieldBytes && fieldBytes % 4 == 0)
    {
      var result = new long[fieldBytes / 4];
      for (int i = 0; i < result.Length; i++) result[i] = BitConverter.ToUInt32(buf, i * sizeof(uint));
      stream.Position = 0; // reset stream-position
      return result;
    }
  }

  // --- fallback for normal gzip-files or unknown structures ---
  stream.Position = 0; // reset stream-position
  return new[] { stream.Length }; // return single default-length
}
static void Main(string[] args)
{
  using (var fileStream = File.OpenRead(@"freebase-rdf-latest.gz"))
  {
    long[] gzipLengths = ReadGzipLengths(fileStream);
    long gzipOffset = 0;

    var buffer = new byte[1048576];
    long total = 0;

    foreach (long gzipLength in gzipLengths)
    {
      fileStream.Position = gzipOffset;

      using (var gz = new GZipStream(fileStream, CompressionMode.Decompress, true)) // true <- don't close FileStream at Dispose()
      {
        int read;
        while ((read = gz.Read(buffer, 0, buffer.Length)) > 0) total += read;
      }

      gzipOffset += gzipLength;

      Console.WriteLine("Uncompressed Bytes: {0:N0} ({1:N2} %)", total, gzipOffset * 100.0 / fileStream.Length);
    }
  }
}
Uncompressed Bytes: 1.945.715.682 (0,47 %)
Uncompressed Bytes: 3.946.888.647 (0,96 %)
Uncompressed Bytes: 5.945.104.284 (1,44 %)
...
...
Uncompressed Bytes: 421.322.787.031 (99,05 %)
Uncompressed Bytes: 423.295.620.069 (99,53 %)
Uncompressed Bytes: 425.229.008.315 (100,00 %)