Использование ZipArchive с веб-API ASP.NET Core

Вопрос в том, как я могу на лету создать заархивированную (сжатую) папку с помощью веб-API ASP.NET Core 2 (в настоящее время)?

Я использую System.IO.Compression.ZipArchive

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

Я могу загрузить zip-папку, но не могу ее открыть.

Заархивированная папка имеет правильный размер. Хотя он не открывается.

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

[HttpGet]
[Route("/api/download/zip")]
public async Task<IActionResult> Zip()
{
    byte[] bytes = null;

    using (MemoryStream zipStream = new MemoryStream())
    using (var zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
    {
        var tempFileName = await _azure.GetFilesByRef("Azure_FilePath");

        // Running just this line gives me the zipped folder (empty) which I can open
        ZipArchiveEntry entry = zip.CreateEntry("File1.pdf", CompressionLevel.Fastest);

        // Adding this 2nd section will download the zip but will not open the zip folder
        using (Stream stream = entry.Open())
        using (FileStream fs = new FileStream(tempFileName, FileMode.Open, FileAccess.Read))
        {
            await fs.CopyToAsync(stream);
        }

        bytes = zipStream.ToArray();
    }

    return File(bytes, MediaTypeNames.Application.Zip, $"Attachments{DateTime.Now.ToBinary()}.zip");
}

Может ли кто-нибудь заметить ошибку или предложить альтернативное решение?

Это работает, если вы отправляете файл напрямую из лазурного? Без застежки? Работает ли он с локальным файлом, полученным не из Azure? Имеет ли смысл размер файла zip-архива?

poke 24.05.2018 19:53

Неясно, пытаетесь ли вы создать zip и отправить его по трубе, или вы пытаетесь получить zip из лазурного и передать его.

Nkosi 24.05.2018 19:55

Вы должны добавить запись для каждого элемента, который хотите добавить в архив.

Nkosi 24.05.2018 20:10

@poke да, я могу скачать файл напрямую с лазурного сервера, но это не та функциональность, которую я хочу.

shammelburg 24.05.2018 20:10

Я говорил о постепенном изменении вашего кода, чтобы вы могли понять, в чем проблема.

poke 24.05.2018 20:15
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
5
4 867
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

memoryStream.ToArray вызывается до того, как архив получит возможность сбросить все свои данные в базовый поток.

Рассмотрите возможность рефакторинга до

//...

var tempFileName = await _azure.GetFilesByRef("Azure_FilePath");
using (MemoryStream zipStream = new MemoryStream()) {
    using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Create, leaveOpen: true)) {            
        ZipArchiveEntry entry = archive.CreateEntry("File1.pdf", CompressionLevel.Fastest);    
        using (Stream stream = entry.Open())
        using (FileStream fs = new FileStream(tempFileName, FileMode.Open, FileAccess.Read)) {
            await fs.CopyToAsync(stream);
        }
    }// disposal of archive will force data to be written to memory stream.
    zipStream.Position = 0; //reset memory stream position.
    bytes = zipStream.ToArray(); //get all flushed data
}

//...

В вашем примере также предполагается, что открытый FileStream является файлом правильного типа для созданной записи; Один файл PDF. В противном случае рассмотрите возможность извлечения имени из tempFileName.

Вы должны добавить уникальную запись (путь к файлу) для каждого элемента, который хотите добавить в архив.

Другие вопросы по теме