下载使用 MVC5 选择的多个文件
Posted
技术标签:
【中文标题】下载使用 MVC5 选择的多个文件【英文标题】:Download multiple files selected with MVC5 【发布时间】:2017-07-29 01:06:24 【问题描述】:我正在 MVC5 中开发一个看起来像这样的视图:
我需要选择表中的一条或多条记录,以便能够下载数据库中以前保存的文件。我一直在寻找解决方案并进行了几次测试,但我找不到解决方案。我试图从 javascript 将所选代码发送到控制器并从中下载文档,但我做不到。如果可以的话,可以下载所有文件并生成一个 zip,或者自动将所有文件下载到浏览器的默认文件夹中。 我将非常感谢任何可以帮助我的人...问候!
这是我的 ajax 调用:
$.ajax(
type: "POST",
url: "/GestionGarantias/Garantias/Download",
data: pCodigo: mCodigo ,//Here I would send the list of //codes, but now to test, I only call the controller regardless of the value, //because the values in the list set them in the handy controller to test.
xhrFields:
responseType: 'blob'
,
success: function (data) //Here should I bring a zip with all files supposedly?
var a = document.createElement('a');
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = 'myfile.zip'; //------------------> I UNDERSTAND THAT THIS IS THE NAME THAT WE SHOULD INDICATE FOR Download ... is it so?
a.click();
window.URL.revokeObjectURL(url);
,
error: function (request, status, errorThrown)
//alert("Se produjo un error al descargar los adjuntos.");
);
我的控制器:
[HttpPost]
public ActionResult Download(List<String> codes)
codes = new List<string>();
codes.Add("1079");
codes.Add("1078");
codes.Add("1077");
MemoryStream ms = null;
foreach (string codigoGar in codes)
string mimetypeOfFile = "";
Garantias oGarantia = ControladorGarantias.getGarantia(SessionHelper.GetEntorno(), codigoGar);
var stream = new MemoryStream(oGarantia.comprobante);
ms = new MemoryStream();
byte[] buffer = new byte[256];
if (stream.Length >= 256)
stream.Read(buffer, 0, 256);
else
stream.Read(buffer, 0, (int)stream.Length);
try
System.UInt32 mimetype;
FindMimeFromData(0, null, buffer, 256, null, 0, out mimetype, 0);
System.IntPtr mimeTypePtr = new IntPtr(mimetype);
mimetypeOfFile = Marshal.PtrToStringUni(mimeTypePtr);
Marshal.FreeCoTaskMem(mimeTypePtr);
catch (Exception e)
return null;
string fileName = "";
if (!string.IsNullOrEmpty(mimetypeOfFile))
switch (mimetypeOfFile.ToLower())
case "application/pdf":
fileName = "Comprobante_" + oGarantia.nombreService + "_" + oGarantia.nroFactura + ".pdf";
break;
case "image/x-png":
fileName = "Comprobante_" + oGarantia.nombreService + "_" + oGarantia.nroFactura + ".png";
break;
case "image/pjpeg":
fileName = "Comprobante_" + oGarantia.nombreService + "_" + oGarantia.nroFactura + ".jpg";
break;
using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, true))
var entry = zip.CreateEntry(fileName);
using (var fileStream = stream)
using (var entryStream = entry.Open())
fileStream.CopyTo(entryStream);
return File(ms.ToArray(), "application/zip");
我所做的是在其中创建一个列表,仅用于测试。 我的想法是针对表中选择的每条记录,找到它们的信息(文件)并将它们添加到 zip 中。
我做错了什么?非常感谢!以及对无知的宽恕。
【问题讨论】:
我将文档作为 varbinary 保存在数据库中。 Palaco - 我已经为您的问题添加了答案。您可以使用该功能,但为此您需要流数据 【参考方案1】:您的问题有两点。首先是获取所有文件的问题,其次是下载文件的问题。在我们解决这些问题之前,让我们退后一步,了解一下请求-响应周期是如何工作的。
使用 HTTP,客户端发出请求,服务器返回响应。重要的是,这里有一个精确的 1-1 相关性。一个请求可以有一个且只有一个响应。这意味着如果您需要提供多个文件作为下载文件,您必须将它们压缩,因为您只能返回一个文件,而不是多个文件。创建一个 zip 文件允许您只返回一个文件,同时仍然满足允许用户一次下载所有文件的要求。
然后是 AJAX 的问题。 JavaScript 中的XMLHttpRequest
对象本质上是一个瘦客户端。它发出 HTTP 请求并接收响应,仅此而已。与通过地址栏导航时 Web 浏览器发出的请求不同,响应不会自动执行,即由您作为开发人员来处理响应并实际执行某些操作。
除此之外,第一部分是创建一个可以返回 zip 文件作为响应的操作。这实际上非常简单:您只需要返回一个FileResult
:
[HttpPost]
public ActionResult DownloadCodes(List<int> codes)
// use codes to get the appropriate files, however you do that
using (var ms = new MemoryStream())
using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, true))
foreach (var file in files)
// write zip archive entries
return File(ms.ToArray(), "application/zip");
对于 zip 存档条目的写入,这取决于文件数据的来源。如果您有文件系统引用,您只需这样做:
zip.CreateEntryFromFile(file, Path.GetFileName(file));
如果您有字节数组,例如从数据库中的 varbinary 列返回的内容:
var entry = zip.CreateEntry(file.Name);
using (var fileStream = new MemoryStream(file.Data))
using (var entryStream = entry.Open())
fileStream.CopyTo(entryStream);
file.Name
和 file.Data
由属性组成,分别指您存储文件名的位置和存储文件数据的位置。
现在,您可以简单地对此操作进行普通表单发布,并且由于响应是在网络浏览器(zip 存档)中无法查看的文件类型,浏览器将自动提示下载。此外,由于这在浏览器中不可见,因此选项卡/窗口中的实际视图也不会改变,从而消除了使用 AJAX 来完成保持在同一页面上的正常需要。但是,您可以根据需要使用 AJAX,但您只能在现代浏览器中处理 AJAX 中的文件响应(基本上除了 IE 10 或更低版本)。如果您不需要支持旧版本的 IE,那么您需要的代码类似于:
jQuery
$.ajax(
url: '/url/to/download/code/action',
data: data // where `data` is what you're posting, i.e. the list of codes
xhrFields:
responseType: 'blob'
,
success: function (data)
// handle file download
);
纯 JavaScript
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function ()
var data = xhr.response;
// handle file download
xhr.open('POST', '/url/to/download/codes/action');
xhr.send();
无论你采用哪种路径,处理文件下载的代码是:
var a = document.createElement('a');
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = 'myfile.pdf';
a.click();
window.URL.revokeObjectURL(url);
【讨论】:
感谢您的解释和贡献,我会尝试这个解决方案,我会尝试这样做。 我为每个与我在 foreach 中的文件对应的代码执行的代码。我的问题如下,假设对于每条记录,我都会创建一个zip文件,或者我将每一个都包含在一个内,因为这就是我需要的,创建一个zip,并且在里面,每一个从之前通过的列表中获得的文件。 使用 (var zip = new ZipArchive(ms, ZipArchiveMode.Create, true)) var entry = zip.CreateEntry(fileName);使用 (var fileStream = stream) 使用 (var entryStream = entry.Open()) fileStream.CopyTo(entryStream); 编写条目的代码将放在我添加// write zip archive entries
注释的位置,该注释位于inside for 循环中。
一千个借口克里斯,我缺的太少了,我认为你已经给了我我需要的东西,我设法生成了包含里面文件的 .rar 文件,但是当我尝试解扰文件后打开它们,就好像文件已损坏,我打开了每种文件类型的应用程序,但没有显示内容,有什么想法吗?我怎样才能向你展示我的方法?是我是新来的页面。也许是一封邮件?【参考方案2】:
使用以下类下载文件:
public class FileDownloadResult : ContentResult
private string fileName;
private Stream fileData;
private bool downloadFlag;
public FileDownloadResult(string fileName, Stream fileData, bool downloadFlag)
this.fileName = fileName;
this.fileData = fileData;
this.downloadFlag = downloadFlag;
public override void ExecuteResult(ControllerContext context)
if (string.IsNullOrEmpty(this.fileName))
throw new Exception("A file name is required.");
if (this.fileData == null)
throw new Exception("File data is required.");
var contentDisposition = "";
if (!downloadFlag)
contentDisposition = string.Format("inline; filename=0", this.fileName);
else
contentDisposition = string.Format("attachment; filename=0", this.fileName);
context.HttpContext.Response.AddHeader("Content-Disposition", contentDisposition);
if (downloadFlag)
ContentType = "application/force-download";
else
if (this.fileName.IndexOf(".pdf", fileName.IndexOf(".")) > 0)
ContentType = "application/pdf";
else if (this.fileName.IndexOf(".csv", fileName.IndexOf(".")) > 0)
ContentType = "application/csv";
else if (this.fileName.IndexOf(".xls", fileName.IndexOf(".")) > 0)
ContentType = "application/xls";
else if (this.fileName.IndexOf(".xlsx", fileName.IndexOf(".")) > 0)
ContentType = "application/xslx";
else
ContentType = "application/txt";
context.HttpContext.Response.AddHeader("Content-Type", ContentType);
byte[] buffer = new byte[1024];
int count = 0;
while ((count = fileData.Read(buffer, 0, buffer.Length)) > 0)
context.HttpContext.Response.OutputStream.Write(buffer, 0, count);
context.HttpContext.Response.Flush();
然后在你的控制器中,使用如下:
public FileDownloadResult Download(string fileName, Stream fileStream)
return new FileDownloadResult(fileName, fileStream, true);
希望对你有帮助:)
【讨论】:
非常感谢 Muhammad Qasim,我会尝试您的解决方案,然后发表评论。 @SebaPalacio - 欢迎您。如果这能解决您的问题,请告诉我,并将其标记为答案,如果对您有帮助,请点赞:) 感谢帮助伙伴,我不处理多个文件,但无论如何谢谢你,或者我不知道如何实现该代码,克里斯,更接近我想要的,设法用他们的代码压缩 zip 文件并下载 Zip,但是在解压缩此 zip 后,文件已损坏,我不明白为什么。无论如何,非常感谢你们!【参考方案3】:我从 @Chris Pratt 那里得到了一些改变,以使其适合我
using (var ms = new MemoryStream())
using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, true))
foreach (var file in files)
// write zip archive entries
zip.CreateEntryFromFile(file, Path.GetFileName(file), CompressionLevel.Optimal);
return File(ms.ToArray(), "application/zip");
【讨论】:
以上是关于下载使用 MVC5 选择的多个文件的主要内容,如果未能解决你的问题,请参考以下文章
MVC5 Identity + EntityFramework 中的多个上下文
C# MVC5 @Html.EnumDropDownListFor 在“回发”上丢失选择
最新版 INSPINIA IN+ - WebApp Admin Theme v2.7.1,包含asp.net MVC5示例代码,做管理系统最佳的选择。