可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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:
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.?
回答1:
You may use the controller's File
method to return a file, like:
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:
public ActionResult Download()
{
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(Server.MapPath("~/Directories/hello"));
MemoryStream output = new MemoryStream();
zip.Save(output);
return File(output, "application/zip", "sample.zip");
}
}
回答2:
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
MemoryStream
instance 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 a MemoryStream
instance 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 MemoryStream class for instructions.
回答3:
just a fix to Klaus solution: (as I can not add comment I have to add another answer!)
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.
so to fix we need to just move return line after using zip block so it works.
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");
}
回答4:
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:
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:
public static List<FileInfo> GetFileInformation()
{
string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
var dirInfo = new DirectoryInfo(path);
return dirInfo.EnumerateFiles().ToList();
}
回答5:
Create a GET
-only controller action that returns a FileResult
, like this:
[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);
}