You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从Web API压缩Azure存储文件返回后解压文件损坏问题

问题分析与修复方案

核心问题点

  • MemoryStream位置未重置:每次将Blob内容下载到memoryStream后,流的Position停在末尾,直接调用StreamUtils.Copy会从末尾开始复制,无法写入有效内容,或后续文件会包含之前所有文件的叠加数据,导致Zip内文件损坏。
  • 重复使用MemoryStream导致内容叠加:循环外创建的memoryStream会累计所有下载的Blob内容,每一次循环都往同一个流里写入,造成后续Zip条目包含错误的文件数据。
  • 冗余代码无意义:代码最后创建了HttpResponseMessage但未实际使用,属于无效代码。

修复后的代码

[HttpPost(nameof(DownloadFiles))]
public async Task<IActionResult> DownloadFiles(List<string> fileNames)
{
    ZipOutputStream zipStream = null;
    try
    {
        MemoryStream outputMemStream = new MemoryStream();
        zipStream = new ZipOutputStream(outputMemStream);
        zipStream.SetLevel(3); // 0-9, 9为最高压缩级别

        string blobstorageconnection = _configuration.GetValue<string>("BlobConnectionString");
        CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(blobstorageconnection);
        CloudBlobClient cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();
        CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference(_configuration.GetValue<string>("BlobContainerName"));

        foreach (string fileName in fileNames)
        {
            CloudBlockBlob blockBlob = cloudBlobContainer.GetBlockBlobReference(fileName);
            // 每次循环新建MemoryStream,避免内容叠加
            using (MemoryStream memoryStream = new MemoryStream())
            {
                await blockBlob.DownloadToStreamAsync(memoryStream);
                // 将流位置重置到起始处,确保Copy读取完整内容
                memoryStream.Position = 0;

                ZipEntry newEntry = new ZipEntry(blockBlob.Name);
                newEntry.DateTime = DateTime.Now;

                zipStream.PutNextEntry(newEntry);
                StreamUtils.Copy(memoryStream, zipStream, new byte[4096]);
                zipStream.CloseEntry();
            }
        }

        zipStream.IsStreamOwner = false; // 关闭ZipStream时不关闭底层流
        zipStream.Close();

        outputMemStream.Position = 0;
        return File(outputMemStream, "application/octet-stream", "Documents.zip");
    }
    finally
    {
        zipStream?.Dispose();
    }
}

关键修复说明

  • 每次循环新建MemoryStream:确保每个Blob的内容独立存储,不会和之前的文件内容叠加。
  • 重置MemoryStream位置:下载完成后将memoryStream.Position设为0,让StreamUtils.Copy能读取完整的Blob内容。
  • 移除冗余代码:直接使用ASP.NET Core的File方法返回流,简化逻辑。
  • 添加资源释放逻辑:通过finally块确保ZipOutputStream在异常情况下也能正确释放,避免资源泄漏。

额外建议

  • 可以添加Blob存在性检查,避免因不存在的文件导致Zip损坏。
  • 处理大文件时,建议采用流式处理而非全部加载到内存,降低内存占用风险。

内容的提问来源于stack exchange,提问作者John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 09:35:23