我正在尝试压缩不同数量的文件,以便可以将一个 zip 文件夹提供给用户,而不必单击多个锚标记。我在 asp.net core 3.1 中使用 System.IO.Compression 命名空间来创建 zip 文件夹。
这是我用来创建 Zip 文件夹的代码。
public IActionResult DownloadPartFiles(string[] fileLocations, string[] fileNames)
{
List<InMemoryFile> files = new List<InMemoryFile>();
for (int i = 0; i < fileNames.Length; i++)
{
InMemoryFile inMemoryFile = GetInMemoryFile(fileLocations[i], fileNames[i]).Result;
files.Add(inMemoryFile);
}
byte[] archiveFile;
using (MemoryStream archiveStream = new MemoryStream())
{
using (ZipArchive archive = new ZipArchive(archiveStream, ZipArchiveMode.Create, true))
{
foreach (InMemoryFile file in files)
{
ZipArchiveEntry zipArchiveEntry = archive.CreateEntry(file.FileName, CompressionLevel.Fastest);
using (Stream zipStream = zipArchiveEntry.Open())
{
zipStream.Write(file.Content, 0, file.Content.Length);
zipStream.Close();
}
}
archiveStream.Position = 0;
}
archiveFile = archiveStream.ToArray();
}
return File(archiveFile, "application/octet-stream");
}
我要压缩的文件是远程存储的,所以我用这段代码来抓取它们。InMemoryFile 是一个将文件名和文件字节组合在一起的类。
private async Task<InMemoryFile> GetInMemoryFile(string fileLocation, string fileName)
{
InMemoryFile file;
using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(fileLocation))
{
byte[] fileContent = await response.Content.ReadAsByteArrayAsync();
file = new InMemoryFile(fileName, fileContent);
}
return file;
}
使用 Ajax 调用 DownloadPartFiles 方法。我使用 javascript 获取文件的远程路径及其各自的名称,并将它们传递给 Ajax 调用。
function downloadAllFiles() {
let partTable = document.getElementById("partTable");
let linkElements = partTable.getElementsByTagName('a');
let urls = [];
for (let i = 0; i < linkElements.length; i++) {
urls.push(linkElements[i].href);
}
if (urls.length != 0) {
var fileNames = [];
for (let i = 0; i < linkElements.length; i++) {
fileNames.push(linkElements[i].innerText);
}
$.ajax({
type: "POST",
url: "/WebOrder/DownloadPartFiles/",
data: { 'fileLocations': urls, 'fileNames': fileNames },
success: function (response) {
var blob = new Blob([response], { type: "application/zip" });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "PartFiles.zip";
link.click();
window.URL.revokeObjectURL(blob);
},
failure: function (response) {
alert(response.responseText);
},
error: function (response) {
alert(response.responseText);
}
});
}
}
现在我一直遇到的问题是我无法在 Windows 10 中打开 zip 文件夹。每次我尝试使用 Windows 或 7-zip 打开 zip 文件夹时,都会收到一条错误消息,指出文件夹无法打开或文件夹无效。我试过在 stackoverflow 上查看各种类似的问题,即使用 System.IO.Compression 创建后的 zip 文件无效,但仍然无法弄清楚这是为什么。
会不会是编码?我发现 Ajax 期望它的响应被编码为 UTF-8,当我使用带有 UTF-8 的 notepad++ 查看 zip 文件时,我看到有指示损坏的字符。
对此的任何想法都会有所帮助。如果需要更多信息,请告诉我。
如果需要其中一个损坏的 zip 文件,我也可以提供。
编辑:
我已经改变了我在 javascript 中接收字节数组的方法。我正在使用 XMLHttpRequest 来接收字节数组。
var parameters = {};
parameters.FileLocations = urls;
parameters.FileNames = fileNames;
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "/WebOrder/DownloadPartFiles/", true);
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.responseType = "arraybuffer";
xmlhttp.onload = function (oEvent) {
var arrayBuffer = xmlhttp.response;
if (arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
var blob = new Blob([byteArray], { type: "application/zip" });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "PartFiles.zip";
link.click();
window.URL.revokeObjectURL(blob);
}
}
xmlhttp.send(JSON.stringify(parameters));
根据我的阅读,Ajax 不是接收字节数组和二进制数据的最佳选择。使用这种方法,我可以使用 7-zip 打开一个 zip 文件,但不能打开 Windows,但是,存档中的一个文件显示为 0KB 大小并且无法打开。存档中的其他三个文件都很好。但是,其他具有不同文件的 zip 文件夹根本无法打开。