Я пытаюсь заархивировать различное количество файлов, чтобы одна zip-папка могла быть предоставлена пользователю вместо того, чтобы щелкать несколько тегов привязки. Я использую пространство имен System.IO.Compression в asp.net core 3.1 для создания 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);
}
});
}
}
Теперь проблема, с которой я продолжаю сталкиваться, заключается в том, что я не могу открыть zip-папку в Windows 10. Каждый раз, когда я пытаюсь открыть zip-папку с помощью Windows или 7-zip, я получаю сообщение об ошибке, что папку нельзя открыть или папка недействительна. Я пытался найти различные похожие проблемы в stackoverflow, т.е. >Недопустимый zip-файл после его создания с помощью System.IO.Compression, но до сих пор не могу понять, почему это так.
Может дело в кодировке? Я обнаружил, что Ajax ожидает, что его ответы будут закодированы в UTF-8, и когда я просматриваю zip-файл с помощью notepad++ с UTF-8, я вижу, что есть символы �, указывающие на повреждение.
Любые мысли по этому поводу будут полезны. Дайте мне знать, если потребуется дополнительная информация.
Если нужен один из поврежденных 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 не лучший вариант для получения байтовых массивов и двоичных данных. С помощью этого метода я смог открыть один из zip-файлов с помощью 7-zip, но не Windows, однако один из файлов в архиве отображался размером 0 КБ и не мог быть открыт. Остальные три файла в архиве были в порядке. Однако другие zip-папки с другими файлами вообще не открывались.
dataType: "html",
? - person Chris G   schedule 09.11.2020