Использование ZipArchive с ASP.NET Core Web Api - PullRequest
0 голосов
/ 24 мая 2018

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

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

IБыло несколько постов в блоге, где это делается с использованием потоков или массивов байтов, и все они дают одинаковый вывод.

Я могу загрузить папку 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");
}

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

1 Ответ

0 голосов
/ 24 мая 2018

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

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.

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

...