从azure blob下载大型zip文件并解压缩



我现在有下面的代码,它使用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.Compression.ZipArchive.Init(流流,ZipArchiveMode模式,布尔leaveOpen(的System.IO.Stream.CopyTo(流目的地,Int32缓冲区大小(处的System.IO.MemoryStream.Write(Byte[]缓冲区,Int32偏移量,Int32计数(

我的zip文件大小是9G。有什么更好的方法可以绕过这个例外?我希望避免将任何文件写入磁盘。

所以这里的问题是

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

因此,您需要允许更大的对象(以某种方式(

允许大型对象

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

然而,在大型对象堆上放置9个gig的任何东西都是有问题的,这对GC和其他问题来说效率低下,而且你应该尽可能地避免LOH。

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

下面的解决方案对我有效。不要使用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);
}
}
}

相关内容

  • 没有找到相关文章

最新更新