【问题标题】:GZipStream in HttpHandler: What am I doing wrong?HttpHandler 中的 GZipStream:我做错了什么?
【发布时间】:2014-05-19 08:59:35
【问题描述】:

我正在写一个HttpHandler,它会根据 GET 请求向客户端发送压缩文件。

这段代码运行良好,可以发送解压后的数据

using (var mem = new MemoryStream())
{
  WriteMyDataToStream(mem);
  context.Response.AddHeader("Content-Type", "application/octet-stream");
  context.Response.AddHeader("Content-Disposition","attachment; filename=file.csv");
  mem.WriteTo(context.Response.OutputStream);
}

但此代码会发送损坏的 zip 文件。

using (var mem = new MemoryStream())
{
   var str = new GZipStream(mem, CompressionMode.Compress);
   WriteMyDataToStream(str);
   context.Response.AddHeader("Content-Type", "application/octet-stream");
   context.Response.AddHeader("Content-Disposition","attachment; filename=file.zip");
   mem.WriteTo(context.Response.OutputStream);
}

请告诉我我做错了什么?

【问题讨论】:

    标签: c# memorystream ihttphandler gzipstream


    【解决方案1】:

    您可以尝试以下方法:

    using (var mem = new MemoryStream())
    {
       using(var str = new GZipStream(mem, CompressionMode.Compress))
       {
          WriteMyDataToStream(str);
          str.Flush();
          context.Response.AddHeader("Content-Type", "application/octet-stream");
          context.Response.AddHeader("Content-Disposition","attachment; filename=file.zip");
          mem.WriteTo(context.Response.OutputStream);
       }
    }
    

    现在应该将所有内容刷新到MemoryStream,然后转发到OutputStream,然后进行处理。

    旁注
    GZipStream 不会像您预期的那样生成 *.zip 文件。正确的扩展名应该是*.gz(参见备注HERE),但大多数解压程序应该都能读取。

    【讨论】:

    • 很好地指出*.gz 扩展名是正确的。我认为DeflateStream 是处理.zip 文件的正确方法。
    • 根据 MSDN DeflateStream 使用与 GZipStream 相同的算法,ZipArchive 应该用于 *.zip...
    • 有用的信息,我好像搞错了。谢谢!
    【解决方案2】:

    您可能需要刷新并显式关闭压缩流,如下所示:

    using (var mem = new MemoryStream())
    {
        using(var str = new GZipStream(mem, CompressionMode.Compress))
        {
            WriteMyDataToStream(str);
            // force the compression stream buffer to be written to the mem stream
            str.Flush(); 
    
        }
        context.Response.AddHeader("Content-Type", "application/octet-stream");
        context.Response.AddHeader("Content-Disposition","attachment; filename=file.zip");
        mem.WriteTo(context.Response.OutputStream);
    }
    

    问题是包装流1 可能使用数据的内部缓冲(就像GZipStream 一样)。这意味着传递给缓冲流的数据将写入其内部缓冲区,但尚未传输到主流。调用Flush() 会导致流将所有缓冲的数据写入目标流并清空缓冲区。

    请注意,处置资源是一种很好的做法。通过在str 变量周围添加using 指令,您还将处理压缩流及其内部缓冲区。


    1包装流 我指的是Stream 实现,它在内部委托给另一个Stream 实例。当在包装流上调用相应的 Write 方法时,可能不会立即写入内部 Stream。此外,内部流本身可以是缓冲流(这意味着在调用 write 方法时数据实际上并未写入流,而是写入缓冲区)。因此,需要在关闭之前刷新包装流,以确保内部流将所有内容写入其中。

    【讨论】:

      猜你喜欢
      • 2011-06-01
      • 1970-01-01
      • 2021-04-14
      • 2021-04-19
      • 2017-03-13
      • 2017-01-18
      • 2013-06-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多