Using ZipArchive with ASP.NET Core Web Api

*爱你&永不变心* 提交于 2019-12-24 02:37:10

问题


The question is how can I create a zipped (compressed) folder on the fly using ASP.NET Core 2 (currently) Web API?

I am using System.IO.Compression.ZipArchive

I have been several blog posts where this is done using streams or byte arrays, all give me the same output.

I am able to download the zip folder but unable to open it.

The zipped folder is the correct size. Even though it doesn't open.

They way I want it to work is for a user to click a button which runs this action and return a zipped folder containing one or multiple files.

[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");
}

Can anyone spot a mistake or suggest an alternative solution?


回答1:


All the data is not written to the stream until the archive is disposed. So in this case, the data in the stream may be incomplete if the archive has not flushed it as yet.

memoryStream.ToArray is being called before the archive has a chance to flush all its data to the underlying stream.

Consider refactoring to

//...

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
}

//...

The assumption in your example is also that the FileStream opened is the correct file type of the created entry; A single PDF file. Otherwise consider extracting a name from the tempFileName.

You have to add a unique entry (file path) for each item you want added to the archive.



来源:https://stackoverflow.com/questions/50513852/using-ziparchive-with-asp-net-core-web-api

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!