【问题标题】:Send a zip file as it is being created在创建时发送 zip 文件
【发布时间】:2017-04-13 09:03:04
【问题描述】:

在我的网站上,当用户单击某个按钮时,必须将一堆文件存档在 zip 中并发送出去。文件本身是由第三方生成的,我只有 URL。 我在这方面取得了部分成功,但我有一些问题。

首先,如果要压缩的文件很多,服务器响应会很慢,因为它先构建压缩文件,然后发送它。它甚至会在一段时间后崩溃(值得注意的是,我收到错误“算术运算中的溢出或下溢。”)。

其次,现在文件只有在 zip 存档完成后才会发送。我希望立即开始下载。也就是说,一旦用户从对话框中单击“保存”,数据就会开始发送,并且随着“动态”创建 zip 文件而继续发送。我在一些网站上看到过这个功能,例如:http://download.muuto.com/

问题是,我不知道该怎么做。

我使用了这个问题的部分代码:Creating a dynamic zip of a bunch of URLs on the fly 来自这篇博文:http://dejanstojanovic.net/aspnet/2015/march/generate-zip-file-on-the-fly-in-aspnet-mvc-application/

zip 文件本身是在 ASP.NET MVC 控制器方法中创建和返回的。这是我的代码:

using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;

namespace MyProject.Controllers
{
    public class MyController : Controller
    {        
        public ActionResult DownloadFiles()
        {
            var files = SomeFunction();

            byte[] buffer = new byte[4096];

            var baseOutputStream = new MemoryStream();
            ZipOutputStream zipOutputStream = new ZipOutputStream(baseOutputStream);
            zipOutputStream.SetLevel(0); //0-9, 9 being the highest level of compression
            zipOutputStream.UseZip64 = UseZip64.Off;
            zipOutputStream.IsStreamOwner = false;

            foreach (var file in files)
            {
                using (WebClient wc = new WebClient())
                {
                    // We open the download stream of the file
                    using (Stream wcStream = wc.OpenRead(file.Url))
                    {
                        ZipEntry entry = new ZipEntry(ZipEntry.CleanName(file.FileName));
                        zipOutputStream.PutNextEntry(entry);

                        // As we read the stream, we add its content to the new zip entry
                        int count = wcStream.Read(buffer, 0, buffer.Length);
                        while (count > 0)
                        {
                            zipOutputStream.Write(buffer, 0, count);
                            count = wcStream.Read(buffer, 0, buffer.Length);
                            if (!Response.IsClientConnected)
                            {
                                break;
                            }
                        }
                    }
                }
            }
            zipOutputStream.Finish();
            zipOutputStream.Close();

            // Set position to 0 so that cient start reading of the stream from the begining
            baseOutputStream.Position = 0;

            // Set custom headers to force browser to download the file instad of trying to open it
            return new FileStreamResult(baseOutputStream, "application/x-zip-compressed")
            {
                FileDownloadName = "Archive.zip"
            };
        }
    }
}

【问题讨论】:

  • 绝对相关(相同目标),但不重复:我正在尝试从 MVC 控制器执行此操作,这是一种不同的方法。我尝试以不同的方式使用BufferOutput = false,但它似乎没有太大变化。
  • 没有什么不同。您可以返回一个FileResult,它接受一个流作为参数

标签: c# asp.net-mvc sharpziplib


【解决方案1】:

好吧,稍微摆弄一下响应输出流和缓冲,我已经找到了解决方案:

using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;

namespace MyProject.Controllers
{
    public class MyController : Controller
    {        
        public ActionResult DownloadFiles()
        {
            var files = SomeFunction();

            // Disable Buffer Output to start the download immediately
            Response.BufferOutput = false;

            // Set custom headers to force browser to download the file instad of trying to open it
            Response.ContentType = "application/x-zip-compressed";
            Response.AppendHeader("content-disposition", "attachment; filename=Archive.zip");

            byte[] buffer = new byte[4096];

            ZipOutputStream zipOutputStream = new ZipOutputStream(Response.OutputStream);
            zipOutputStream.SetLevel(0); // No compression
            zipOutputStream.UseZip64 = UseZip64.Off;
            zipOutputStream.IsStreamOwner = false;

            try
            {
                foreach (var file in files)
                {
                    using (WebClient wc = new WebClient())
                    {
                        // We open the download stream of the image
                        using (Stream wcStream = wc.OpenRead(file.Url))
                        {
                            ZipEntry entry = new ZipEntry(ZipEntry.CleanName(file.FileName));
                            zipOutputStream.PutNextEntry(entry);

                            // As we read the stream, we add its content to the new zip entry
                            int count = wcStream.Read(buffer, 0, buffer.Length);
                            while (count > 0)
                            {
                                zipOutputStream.Write(buffer, 0, count);
                                count = wcStream.Read(buffer, 0, buffer.Length);
                                if (!Response.IsClientConnected)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                zipOutputStream.Finish();
                zipOutputStream.Close();
            }

            return new HttpStatusCodeResult(HttpStatusCode.OK);
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-07
    • 2013-07-11
    • 1970-01-01
    • 2019-10-23
    • 2018-08-17
    • 2015-03-13
    • 2022-06-11
    相关资源
    最近更新 更多