如何使用GZipStream解压缩内存中的gz文件?

问题描述:

我可能在这里做一些明显愚蠢的事情。请指出!如何使用GZipStream解压缩内存中的gz文件?

我有一些C#代码是从SFTP下拉一堆.gz文件(使用SSH.NET Nuget package - 效果很好!)。每个gz在其中只包含一个.CSV文件。我想将这些文件保存在内存中而不会触及磁盘(是的,我知道存在服务器内存管理问题 - 这些文件相当小),在内存中解压缩以提取CSV文件,然后返回自定义DTO中的CSV文件(FtpFile)。

我的问题是,虽然我从SFTP连接的MemoryStream中有数据,但它似乎没有填充在我的GZipStream中,或者从GZipStream复制到我的输出MemoryStream失败。我已经尝试了使用我自己的缓冲区读取更传统的循环,但它具有与此代码相同的结果。

从连接细节

除了(连接成功,所以不用担心有),这里是我的全部代码:

逻辑

public static List<FtpFile> Foo() 
    { 
     var connectionInfo = new ConnectionInfo("example.com", 
      "username", 
      new PasswordAuthenticationMethod("username", "password")); 
     using (var client = new SftpClient(connectionInfo)) 
     { 
      client.Connect(); 

      var searchResults = client.ListDirectory("/testdir") 
       .Where(obj => obj.IsRegularFile 
           && obj.Name.ToLowerInvariant().StartsWith("test_") 
           && obj.Name.ToLowerInvariant().EndsWith(".gz")) 
       .Take(2) 
       .ToList(); 

      var fileResults = new List<FtpFile>(); 

      foreach (var file in searchResults) 
      { 
       var ftpFile = new FtpFile { FileName = file.Name, FileSize = file.Length }; 

       using (var fileStream = new MemoryStream()) 
       { 
        client.DownloadFile(file.FullName, fileStream); // Success! All is good here, so far. :) 

        using (var gzStream = new GZipStream(fileStream, CompressionMode.Decompress)) 
        { 
         using (var outputStream = new MemoryStream()) 
         { 
          gzStream.CopyTo(outputStream); 
          byte[] outputBytes = outputStream.ToArray(); // No data. Sad panda. :'(
          ftpFile.FileContents = Encoding.ASCII.GetString(outputBytes); 
          fileResults.Add(ftpFile); 
         } 
        } 
       } 
      } 

      return fileResults; 
     } 
    } 

FtpFile(只是一个简单的DTO我”米填充):

public class FtpFile 
{ 
    public string FileName { get; set; } 
    public long FileSize { get; set; } 
    public string FileContents { get; set; } 
} 

PSA如果有人来复制此代码,请注意,这是不好的代码,你可能有一些严重这个代码的内存管理问题!这是最好的做法,而不是流到磁盘,这是而不是正在执行此代码!我的需求非常具体,因为我必须将这些文件同时存储在内存中,以便与我一起构建它们。

+0

是gzip压缩值是否有效?如果你检查gzip字节[],如果它的长度为10,并且具有以下序列:31,139,8,0,0,0,0,0,4,0。这意味着它没有被正确地压缩。 – StfBln

+0

@StfBln GZipped值的长度为1884,从该序列开始:31,139,8,0,120,192,198,88。此外,这是来自第三方生产系统,迄今为止我们在初始测试中手动处理这些gz文件没有问题。 – Jaxidian

+1

“client.DownloadFile(file.FullName,fileStream)”是否倒回流?否则fileStream需要使用“Seek(0,SeekOrigin.Begin)” – StfBln

如果您要将数据插入流中,请务必在解压缩数据之前找回其来源。

下应解决您的烦恼:

  using (var fileStream = new MemoryStream()) 
      { 
       client.DownloadFile(file.FullName, fileStream); // Success! All is good here, so far. :) 
       fileStream.Seek(0, SeekOrigin.Begin); 

       using (var gzStream = new GZipStream(fileStream, CompressionMode.Decompress)) 
       { 
        using (var outputStream = new MemoryStream()) 
        { 
         gzStream.CopyTo(outputStream); 
         byte[] outputBytes = outputStream.ToArray(); // No data. Sad panda. :'(
         ftpFile.FileContents = Encoding.ASCII.GetString(outputBytes); 
         fileResults.Add(ftpFile); 
        } 
       } 
      } 
+0

这就是它!谢谢!!这与'fileStream.Position = 0;'是一样的吗?还是两者不同? – Jaxidian

+1

@Jaxidian fileStream.Position = 0;应该也能工作。请参阅http://*.com/questions/7238929/stream-seek0-seekorigin-begin-or-position-0了解更多信息。 – StfBln

+0

再次感谢! :-) – Jaxidian