C# 使用 DotNetZip 通过 ASP.NET MVC 下载 zip 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29907291/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Downloading of zip file through ASP.NET MVC using DotNetZip
提问by user2801336
I have created a text file in a folder and zipped that folder and saved @same location for test purpose. I wanted to download that zip file directly on user machine after it is created. I am using dotnetzip library and have done following:
我在一个文件夹中创建了一个文本文件并压缩了该文件夹并保存了@same 位置以供测试。我想在创建后直接在用户计算机上下载该 zip 文件。我正在使用 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 文件。?
采纳答案by mcserep
You may use the controller's Filemethod 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");
}
}
回答by Karl Anderson
Create a GET-only controller action that returns a FileResult, like this:
创建一个GET返回 a的仅控制器操作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);
}
回答by Alex Klaus
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:
上面代码的注释:
- Passing a
MemoryStreaminstance requires checks that it's open, valid and etc. I omitted them. I'd rather passed a byte array of the file content instead of aMemoryStreaminstance to make the code more robust, but it'd be too much for this example. - It doesn't show how to create a required context (your file) in memory. I'd refer to MemoryStreamclass for instructions.
- 传递一个
MemoryStream实例需要检查它是开放的、有效的等等。我省略了它们。我宁愿传递文件内容的字节数组而不是MemoryStream实例以使代码更健壮,但对于此示例来说太多了。 - 它没有显示如何在内存中创建所需的上下文(您的文件)。我会参考MemoryStream类的说明。
回答by John Peters
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:
Get File 是一种扩展方法:
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();
}
回答by HamedH
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. the final result is :
所以要修复,我们需要在使用 zip 块后移动返回行,这样它就可以工作了。最终结果是:
/// <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");
}

