Не удается открыть zip-файл, созданный из пространства имен System.IO.Compression.

Я пытаюсь заархивировать различное количество файлов, чтобы одна 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-папки с другими файлами вообще не открывались.


person Chase T    schedule 09.11.2020    source источник
comment
Вы отладили это, чтобы убедиться, что данные, которые вы отправляете через запрос POST, получены правильно? Кроме того, почему в параметрах запроса указано dataType: "html",?   -  person Chris G    schedule 09.11.2020
comment
Да, файловые местоположения и имена файлов проходят нормально. Что касается типа данных, это было ошибкой с моей стороны. Я удалил это, но все равно получаю тот же результат.   -  person Chase T    schedule 09.11.2020


Ответы (1)


Через некоторое время я нашел сообщение, которое помогло решить мою проблему: Создать 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");
        }

Я до сих пор не знаю, почему у предыдущего метода были проблемы, поэтому, если кто-нибудь знает ответ на этот вопрос в будущем, я бы хотел узнать.

person Chase T    schedule 19.11.2020