无法打开从 System.IO.Compression 命名空间创建的 zip 文件



我正在尝试压缩不同数量的文件,以便一个zip文件夹可以提供给用户,而不必单击多个锚点标签。我正在使用asp.net核心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;
}

DownloadPartFiles方法是使用Ajax调用的。我使用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编码的,当我使用notepad++和UTF-8查看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文件夹根本无法打开。

过了一段时间,我发现了一篇能够解决我的问题的帖子,从byte[]创建zip文件

从那篇文章来看,这是我用来创建一个包含文件的zip文件夹的修订方法

public IActionResult DownloadPartFiles([FromBody] FileRequestParameters parameters)
{
List<InMemoryFile> files = new List<InMemoryFile>();
for (int i = 0; i < parameters.FileNames.Length; i++)
{
InMemoryFile inMemoryFile = GetInMemoryFile(parameters.FileLocations[i], parameters.FileNames[i]).Result;
files.Add(inMemoryFile);
}
byte[] archiveFile = null;
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.Optimal);
using (MemoryStream originalFileStream = new MemoryStream(file.Content))
using (Stream zipStream = zipArchiveEntry.Open())
{
originalFileStream.CopyTo(zipStream);
}
}
}
archiveFile = archiveStream.ToArray();
}
return File(archiveFile, "application/octet-stream");
}

我仍然不知道为什么以前的方法会出现问题,所以如果将来有人知道答案,我很想知道。

最新更新