2014-05-19 26 views
0

我在写一个HttpHandler,它在GET请求上向客户端发送压缩文件。HttpHandler中的GZipStream:我做错了什么?

此代码工作得很好,将解压后的数据

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); 
} 

但是这个代码将破拉链文件。

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); 
} 

请告诉我我做错了什么?

回答

2

你可以尝试以下方法:

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),但大多数解压缩程序应该能够读取它。

+1

很好的指出'* .gz'的扩展名是正确的。我认为'DeflateStream'是解决'.zip'文件的正确方法。 –

+1

根据MSDN'DeflateStream'使用与'GZipStream'相同的算法,'ZipArchive'应该用于*'.zip' ... – ChrFin

+0

有用的信息,我似乎误会了。谢谢! –

1

您可能需要刷新,并明确关闭压缩流,就像这样:

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); 
} 

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

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


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