在ASP.NET Core Web Api中使用ZipArchive

3

问题是如何使用ASP.NET Core 2 Web API动态创建一个压缩的文件夹?

我正在使用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");
}

有人能发现错误或提供另一种解决方案吗?

1
如果直接从Azure发送文件而不进行压缩,它能正常工作吗?如果本地文件不来自Azure,它能正常工作吗?压缩文件的大小是否合理? - poke
不清楚你是想创建一个 zip 并通过管道发送还是想从 Azure 获取一个 zip 并传递它。 - Nkosi
您需要为想要添加到归档中的每个项目添加一个条目。 - Nkosi
@poke 是的,我可以直接从 Azure 下载文件,但这不是我想要的功能。 - shammelburg
我在谈论逐步修改您的代码,以便您可以找出问题所在。 - poke
1个回答

7

只有在归档文件被处理后才会将所有数据写入流中。因此,在这种情况下,如果归档文件尚未刷新数据,流中的数据可能是不完整的。

在调用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中提取名称。
您必须为您想要添加到归档中的每个项目添加一个唯一的条目(文件路径)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接