简体   繁体   English

使用DotNetZip通过ASP.NET MVC下载zip文件

[英]Downloading of zip file through ASP.NET MVC using DotNetZip

I have created a text file in a folder and zipped that folder and saved @same location for test purpose. 我在文件夹中创建了一个文本文件并压缩了该文件夹并保存了@same位置以供测试。 I wanted to download that zip file directly on user machine after it is created. 我想在创建后直接在用户计算机上下载该zip文件。 I am using dotnetzip library and have done following: 我正在使用dotnetzip库并完成以下操作:

Response.Clear();
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "filename=" + "sample.zip");
using (ZipFile zip = new ZipFile())
{
    zip.AddDirectory(Server.MapPath("~/Directories/hello"));
    zip.Save(Server.MapPath("~/Directories/hello/sample.zip"));
}

Can someone please suggest how the zip file can be downloaded at user's end.? 有人可以建议如何在用户端下载zip文件。

You may use the controller's File method to return a file, like: 您可以使用控制器的File方法返回文件,例如:

public ActionResult Download()
{
    using (ZipFile zip = new ZipFile())
    {
        zip.AddDirectory(Server.MapPath("~/Directories/hello"));
        zip.Save(Server.MapPath("~/Directories/hello/sample.zip"));
        return File(Server.MapPath("~/Directories/hello/sample.zip"), 
                                   "application/zip", "sample.zip");
    }
}

If the zip file is not required otherwise to be stored, it is unnecessary to write it into a file on the server: 如果不需要存储zip文件,则无需将其写入服务器上的文件:

public ActionResult Download()
{
    using (ZipFile zip = new ZipFile())
    {
        zip.AddDirectory(Server.MapPath("~/Directories/hello"));

        MemoryStream output = new MemoryStream();
        zip.Save(output);
        return File(output.ToArray(), "application/zip", "sample.zip");
    }  
}

First of all, consider a way without creating any files on the server's disk. 首先,考虑一种不在服务器磁盘上创建任何文件的方法。 Bad practise. 不好的做法。 I'd recommend creating a file and zipping it in memory instead. 我建议创建一个文件并将其压缩到内存中。 Hope, you'll find my example below useful. 希望,你会发现下面的例子很有用。

/// <summary>
///     Zip a file stream
/// </summary>
/// <param name="originalFileStream"> MemoryStream with original file </param>
/// <param name="fileName"> Name of the file in the ZIP container </param>
/// <returns> Return byte array of zipped file </returns>
private byte[] GetZippedFiles(MemoryStream originalFileStream, string fileName)
{
    using (MemoryStream zipStream = new MemoryStream())
    {
        using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
        {
            var zipEntry = zip.CreateEntry(fileName);
            using (var writer = new StreamWriter(zipEntry.Open()))
            {
                originalFileStream.WriteTo(writer.BaseStream);
            }
            return zipStream.ToArray();
        }
    }
}

/// <summary>
///     Download zipped file
/// </summary>
[HttpGet]
public FileContentResult Download()
{
    var zippedFile = GetZippedFiles(/* your stream of original file */, "hello");
    return File(zippedFile, // We could use just Stream, but the compiler gets a warning: "ObjectDisposedException: Cannot access a closed Stream" then.
                "application/zip",
                "sample.zip");
}

Notes to the code above: 上面代码的注释:

  1. Passing a MemoryStream instance requires checks that it's open, valid and etc. I omitted them. 传递一个MemoryStream实例需要检查它是否打开,有效等等。我省略了它们。 I'd rather passed a byte array of the file content instead of a MemoryStream instance to make the code more robust, but it'd be too much for this example. 我宁愿传递文件内容的字节数组而不是MemoryStream实例来使代码更健壮,但对于这个例子来说太过分了。
  2. It doesn't show how to create a required context (your file) in memory. 它没有显示如何在内存中创建所需的上下文(您的文件)。 I'd refer to MemoryStream class for instructions. 我将引用MemoryStream类来获取指令。

just a fix to Klaus solution: (as I can not add comment I have to add another answer!) 只是对Klaus解决方案的修复:(因为我无法添加评论,我必须添加另一个答案!)

The solution is great but for me it gave corrupted zip file and I realized that it is because of return is before finalizing zip object so it did not close zip and result in a corrupted zip. 解决方案很棒,但对我来说它提供了损坏的zip文件,我意识到这是因为返回是在最终确定zip对象之前所以它没有关闭zip并导致损坏的zip。

so to fix we need to just move return line after using zip block so it works. 所以为了解决这个问题,我们需要在使用zip块之后移动返回线,以便它可以工作。 the final result is : 最终结果是:

/// <summary>
///     Zip a file stream
/// </summary>
/// <param name="originalFileStream"> MemoryStream with original file </param>
/// <param name="fileName"> Name of the file in the ZIP container </param>
/// <returns> Return byte array of zipped file </returns>
private byte[] GetZippedFiles(MemoryStream originalFileStream, string fileName)
{
    using (MemoryStream zipStream = new MemoryStream())
    {
        using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
        {
            var zipEntry = zip.CreateEntry(fileName);
            using (var writer = new StreamWriter(zipEntry.Open()))
            {
                originalFileStream.WriteTo(writer.BaseStream);
            }
        }
        return zipStream.ToArray();
    }
}

/// <summary>
///     Download zipped file
/// </summary>
[HttpGet]
public FileContentResult Download()
{
    var zippedFile = GetZippedFiles(/* your stream of original file */, "hello");
    return File(zippedFile, // We could use just Stream, but the compiler gets a warning: "ObjectDisposedException: Cannot access a closed Stream" then.
                "application/zip",
                "sample.zip");
}

For those just wanting to return an existing Zip file from the App_Data folder (just dump in your zip files there), in the Home controller create this action method: 对于那些只想从App_Data文件夹中返回现有Zip文件的人(只在那里转储zip文件),在Home控制器中创建此操作方法:

    public FileResult DownLoad(string filename)
    {
        var content = XFile.GetFile(filename);
        return File(content, System.Net.Mime.MediaTypeNames.Application.Zip, filename);

    }

Get File is an extention method: 获取文件是一种扩展方法:

   public static byte[] GetFile(string name)
    {
        string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
        string filenanme = path + "/" + name;
        byte[] bytes = File.ReadAllBytes(filenanme);
        return bytes;
    }

Home controller Index view looks like this: 家庭控制器索引视图如下所示:

@model  List<FileInfo>

<table class="table">
    <tr>
        <th>
            @Html.DisplayName("File Name")
        </th>
        <th>
            @Html.DisplayName("Last Write Time")
        </th>
        <th>
            @Html.DisplayName("Length (mb)")
        </th>
        <th></th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.ActionLink("DownLoad","DownLoad",new {filename=item.Name})
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.LastWriteTime)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Length)
            </td>
        </tr>
    }
</table>

The main index file action method: 主索引文件操作方法:

    public ActionResult Index()
    {
        var names = XFile.GetFileInformation();
        return View(names);
    }

Where GetFileInformation is an extension method: GetFileInformation是一个扩展方法:

    public static List<FileInfo> GetFileInformation()
    {
        string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
        var dirInfo = new DirectoryInfo(path);
        return dirInfo.EnumerateFiles().ToList();
    }

Create a GET -only controller action that returns a FileResult , like this: 创建一个返回FileResultGET FileResult控制器操作,如下所示:

[HttpGet]
public FileResult Download()
{   
    // Create file on disk
    using (ZipFile zip = new ZipFile())
    {
        zip.AddDirectory(Server.MapPath("~/Directories/hello"));
        //zip.Save(Response.OutputStream);
        zip.Save(Server.MapPath("~/Directories/hello/sample.zip"));
    }

    // Read bytes from disk
    byte[] fileBytes = System.IO.File.ReadAllBytes(
        Server.MapPath("~/Directories/hello/sample.zip"));
    string fileName = "sample.zip";

    // Return bytes as stream for download
    return File(fileBytes, "application/zip", fileName);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM