如何实时压缩并实时流式传输到Response.Output?

10 asp.net zip outputstream real-time sharpziplib

我试图使用以下代码:我得到一个损坏的zip文件.为什么?文件名似乎没问题.也许他们不是相对的名字,这就是问题所在?

      private void trySharpZipLib(ArrayList filesToInclude)
    {
        // Response header
        Response.Clear();
        Response.ClearHeaders();
        Response.Cache.SetCacheability(HttpCacheability.NoCache);
        Response.StatusCode = 200; // http://community.icsharpcode.net/forums/p/6946/20138.aspx
        long zipSize = calculateZipSize(filesToInclude);
        string contentValue = 
            string.Format("attachment; filename=moshe.zip;"
                          ); // + " size={0}", zipSize);
        Response.ContentType = "application/octet-stream"; //"application/zip"; 
        Response.AddHeader("Content-Disposition", contentValue);
        Response.Flush();

        using (ZipOutputStream zipOutputStream = new ZipOutputStream(Response.OutputStream) ) 
        {
            zipOutputStream.SetLevel(0);

            foreach (string f in filesToInclude)
            {
                string filename = Path.Combine(Server.MapPath("."), f);
                using (FileStream fs = File.OpenRead(filename))
                {
                    ZipEntry entry =
                        new ZipEntry(ZipEntry.CleanName(filename))
                            {
                                DateTime = File.GetCreationTime(filename),
                                CompressionMethod = CompressionMethod.Stored,
                                Size = fs.Length
                            };
                    zipOutputStream.PutNextEntry(entry);

                    byte[] buffer = new byte[fs.Length];
                    // write to zipoutStream via buffer. 
                    // The zipoutStream is directly connected to Response.Output (in the constructor)
                    ICSharpCode.SharpZipLib.Core.StreamUtils.Copy(fs, zipOutputStream, buffer); 
                    Response.Flush(); // for immediate response to user
                } // .. using file stream
            }// .. each file
        }
        Response.Flush();
        Response.End();
    }
Run Code Online (Sandbox Code Playgroud)

Che*_*eso 14

男孩,这是很多代码!使用DotNetZip可以简化您的工作.假设HTTP 1.1客户端,这适用:

Response.Clear();
Response.BufferOutput = false;
string archiveName= String.Format("archive-{0}.zip", DateTime.Now.ToString("yyyy-MMM-dd-HHmmss"));
Response.ContentType = "application/zip";
// see http://support.microsoft.com/kb/260519
Response.AddHeader("content-disposition", "attachment; filename=" + archiveName);  
using (ZipFile zip = new ZipFile())
{
    // filesToInclude is a IEnumerable<String> (String[] or List<String> etc)
    zip.AddFiles(filesToInclude, "files");
    zip.Save(Response.OutputStream);
}
// Response.End(); // will throw an exception internally.
// Response.Close(); // Results in 'Failed - Network error' in Chrome.
Response.Flush(); // See https://stackoverflow.com/a/736462/481207
// ...more code here...
Run Code Online (Sandbox Code Playgroud)

如果要对zip进行密码加密,则在AddFiles()之前插入以下行:

    zip.Password = tbPassword.Text; // optional
    zip.Encryption = EncryptionAlgorithm.WinZipAes256; // optional
Run Code Online (Sandbox Code Playgroud)

如果需要自解压存档,请将zip.Save()替换为zip.SaveSelfExtractor().


附录; 有些人评论说DotNetZip"不好",因为它在流式传输之前在内存中创建了整个ZIP.事实并非如此.当您调用AddFiles时,库会创建一个条目列表 - 表示要压缩的事物的状态的对象.在调用Save之前,没有进行压缩或加密.如果指定Save()调用的流,则所有压缩的字节将直接流式传输到客户端.

在SharpZipLib模型中,可以创建一个条目,然后将其流出,然后创建另一个条目,然后将其流出,依此类推.使用DotNetZip,您的应用程序首先创建完整的条目列表,然后将它们全部流出.这两种方法都不一定比其他方法"更快",但对于长文件列表,例如30,000,使用SharpZipLib时,第一字节的时间会更快.另一方面,我不建议动态创建包含30,000个条目的zip文件.


编辑

从DotNetZip v1.9开始,DotNetZip也支持ZipOutputStream.我仍然认为按照我在这里展示的方式做事更简单.


有些人的情况是,所有用户都拥有"大致相同"的zip内容,但每个用户的文件都有不同.DotNetZip也很擅长这一点.您可以从文件系统文件中读取zip存档,更新一些条目(添加一些,删除一些等),然后保存到Response.OutputStream.在这种情况下,DotNetZip不会重新压缩或重新加密您未更改的任何条目.快多了.

当然DotNetZip适用于任何.NET应用程序,而不仅仅是ASP.NET.所以你可以保存到任何流.

如果您想了解更多信息,请查看网站或在dotnetzip论坛发帖.


ala*_*lin 0

尝试添加以下标头。

Response.AddHeader("Content-Length", zipSize);
Run Code Online (Sandbox Code Playgroud)

我知道这之前给我带来了问题。

编辑:

其他 2 个也可能有帮助:

Response.AddHeader("Content-Description", "File Transfer");
Response.AddHeader("Content-Transfer-Encoding", "binary");
Run Code Online (Sandbox Code Playgroud)