【问题标题】:Download large zip file from azure blob and unzip从 azure blob 下载大 zip 文件并解压缩
【发布时间】:2021-03-03 11:25:03
【问题描述】:

我目前有以下代码,它使用 SAS URI 从 blob 下载 zip 文件,解压缩并将内容上传到新容器

        var response = await new BlobClient(new Uri(sasUri)).DownloadAsync();
        using (ZipArchive archive = new ZipArchive(response.Value.Content))
        {
            foreach (ZipArchiveEntry entry in archive.Entries)
            {
                BlobClient blobClient = _blobServiceClient.GetBlobContainerClient(containerName).GetBlobClient(entry.FullName);
                using (var fileStream = entry.Open())
                {
                    await blobClient.UploadAsync(fileStream, true);
                }
            }
        }

我的代码因“流太长”异常而失败:System.IO.IOException:流太长。在 System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count) 在 System.IO.Stream.CopyTo(Stream destination, Int32 bufferSize) 在 System.IO.Compression.ZipArchive.Init(Stream stream, ZipArchiveMode模式,布尔值 leaveOpen).

我的 zip 文件大小为 9G。解决此异常的更好方法是什么?我想避免将任何文件写入磁盘。

【问题讨论】:

  • 这个框架还是核心?
  • 是点网核心
  • 我不熟悉 Azure API,DownloadAsync 是否会将整个内容下载到内存中,或者它会返回一个流并在下载内容时对其进行处理?也许 ZipArchive 可以在流上工作而无需将整个内容下载到内存中?
  • 你弄明白了吗?
  • @Tarostar 发布解决方案

标签: c# .net .net-core azure-blob-storage ziparchive


【解决方案1】:

所以这里的问题是

  1. .Net 的数组大小有限(取决于平台)。
  2. 数组作为缓冲区或内存数据存储返回
  3. 在 64 位平台上,数组大小为 2 GB
  4. 您想在大对象堆上放置一个 9 gig 流(由数组支持)。

因此,您将需要允许更大的对象(不知何故)

Allow large objects

  • 在 .Net Framework 4.5+ 中,您可以设置 <gcAllowVeryLargeObjects> 项目元素
  • 在核心中,您需要设置 环境变量 COMPlus_gcAllowVeryLargeObjects

但是,在 大型对象堆 上放置 9 个 gig 的东西是有问题的,这对于 GC 以及其他问题来说效率低下,您应该尽可能避免 LOH。

请注意,具体取决于库以及您可以访问的内容。可能有更少的LOHy 方法来做到这一点。如果您可以提供自己的流/数据结构,那么有一些库可以分解缓冲区,这样它们就不会通过ReadOnlySequence 和微软鲜为人知的RecyclableMemoryStream 之类的东西在 LOH 上被积极分配。

【讨论】:

  • 谢谢,我试试环境变量。我正在使用标准的 azure blob 和 dot net 压缩库。您对其他哪些库会更好有什么建议吗?
  • @user1097128 不,令人惊讶的是,我从来没有真正需要这种类型的 zip 恶作剧。如果您找到解决方案,请务必发布它
【解决方案2】:

以下解决方案对我有用。不要使用 DownloadAsync,而是使用 OpenReadAsync

var response = await new BlobClient(new Uri(sasUri)).OpenReadAsync(new BlobOpenReadOptions(false), cancellationToken);
using (ZipArchive archive = new ZipArchive(response))
{
    foreach (ZipArchiveEntry entry in archive.Entries)
    {
        BlobClient blobClient = _blobServiceClient.GetBlobContainerClient(containerName).GetBlobClient($"{buildVersion}/{entry.FullName}");
        using (var fileStream = entry.Open())
        {
           await blobClient.UploadAsync(fileStream, true, cancellationToken).ConfigureAwait(false);
        }
    }
}

【讨论】:

    猜你喜欢
    • 2021-03-07
    • 1970-01-01
    • 1970-01-01
    • 2011-05-28
    • 2016-01-15
    • 1970-01-01
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多