Загрузите zip-файл небольшими порциями в azure облачное хранилище больших двоичных объектов. - PullRequest
0 голосов
/ 04 февраля 2020

Я хочу загрузить zip-файл небольшими порциями (менее 5 МБ) для создания блоб-контейнеров в Microsoft Azure Storage. Я уже настроил ограничения блоков 4 МБ в BlobRequestOptions, но когда я запускаю свой код и проверяю использование памяти в Azure Cloud, он не загружается частями. Я использую C#. NET Core. Поскольку я хочу архивировать файлы, которые уже находятся в Azure Cloud, поэтому сначала я загружаю отдельные файлы в поток, добавляю поток в архив zip и затем загружаю zip обратно в облако. Ниже приведен мой код:

if (CloudStorageAccount.TryParse(_Appsettings.GetSection("StorConf").GetSection("StorageConnection").Value, out CloudStorageAccount storageAccount)) {
 CloudBlobClient BlobClient = storageAccount.CreateCloudBlobClient();

 TimeSpan backOffPeriod = TimeSpan.FromSeconds(2);
 int retryCount = 1;
 BlobRequestOptions bro = new BlobRequestOptions() {


  SingleBlobUploadThresholdInBytes = 4096 * 1024, // 4MB
   ParallelOperationThreadCount = 1,
   RetryPolicy = new ExponentialRetry(backOffPeriod, retryCount),
   // new
   ServerTimeout = TimeSpan.MaxValue,
   MaximumExecutionTime = TimeSpan.FromHours(3),
   //EncryptionPolicy = policy
 };



 // set blob request option for created blob client
 BlobClient.DefaultRequestOptions = bro;

 // using specified container which comes via transaction id
 CloudBlobContainer container = BlobClient.GetContainerReference(transaction id);

 using(var zipArchiveMemoryStream = new MemoryStream()) {
  using(var zipArchive = new ZipArchive(zipArchiveMemoryStream, ZipArchiveMode.Create, true)) // new
  {

   foreach(FilesListModel FileName in filesList) {

    if (await container.ExistsAsync()) {
     CloudBlob file = container.GetBlobReference(FileName.FileName);

     if (await file.ExistsAsync()) {
      // zip: get stream and add zip entry
      var entry = zipArchive.CreateEntry(FileName.FileName, CompressionLevel.Fastest);

      // approach 1
      using(var entryStream = entry.Open()) {
       await file.DownloadToStreamAsync(entryStream, null, bro, null);

       await entryStream.FlushAsync();

       entryStream.Close();
      }
     } else {
      downlReady = "false";
     }
    } else {
     // case: Container does not exist

     //return BadRequest("Container does not exist");

    }
   }
  }

  if (downlReady == "true") {
   string zipFileName = "sample.zip";
   CloudBlockBlob zipBlockBlob = container.GetBlockBlobReference(zipFileName);

   zipArchiveMemoryStream.Position = 0;
   //zipArchiveMemoryStream.Seek(0, SeekOrigin.Begin);

   // new
   zipBlockBlob.Properties.ContentType = "application/x-zip-compressed";

   await zipArchiveMemoryStream.FlushAsync();

   await zipBlockBlob.UploadFromStreamAsync(zipArchiveMemoryStream, zipArchiveMemoryStream.Length, null, bro, null);
  }

  zipArchiveMemoryStream.Close();

 }
}

Ниже приведен снимок использования памяти (см. Private_Memory) в azure проводнике процесса облачного куду:

использование памяти

Любые предложения будут действительно полезны. Спасибо.

ОБНОВЛЕНИЕ 1:

Чтобы было понятнее. У меня есть файлы, которые уже находятся в Azure хранилище BLOB-объектов. Теперь я хочу прочитать файлы из контейнера, создать ZIP, который содержит все мои файлы. Основная проблема здесь заключается в том, что мой код, очевидно, загружает все файлы в память для создания zip. Если и как можно считывать файлы из контейнера и записывать ZIP-файл обратно в тот же контейнер параллельно / кусками, чтобы моему веб-приложению Azure НЕ нужно было загружать все файлы в память? В идеале я читаю файлы по частям, а также начинаю писать zip, так что мое Azure веб-приложение потребляет меньше памяти.

1 Ответ

0 голосов
/ 06 февраля 2020

Я нашел решение, обратившись к этой статье stackoverflow:

Как я могу динамически добавлять файлы в zip-архив, хранящийся в Azure хранилище BLOB-объектов?

Способ сделать это - одновременно выполнить запись в поток zip-памяти при чтении / загрузке входных файлов.

Ниже приведен фрагмент кода:

                using (var zipArchiveMemoryStream = await zipBlockBlob.OpenWriteAsync(null, bro, null))
                using (var zipArchive = new ZipArchive(zipArchiveMemoryStream, ZipArchiveMode.Create))
                {

                    foreach (FilesListModel FileName in filesList)
                    {
                        if (await container.ExistsAsync())
                        {
                            CloudBlob file = container.GetBlobReference(FileName.FileName);

                            if (await file.ExistsAsync())
                            {
                                // zip: get stream and add zip entry
                                var entry = zipArchive.CreateEntry(FileName.FileName, CompressionLevel.Fastest);

                                // approach 1
                                using (var entryStream = entry.Open())
                                {
                                    await file.DownloadToStreamAsync(entryStream, null, bro, null);
                                    entryStream.Close();
                                }
                            }
                        }
                    }
                    zipArchiveMemoryStream.Close();

}

...