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

У меня есть процесс в Azure, который генерирует большое количество файлов отчетов в формате pdf и сохраняет их в хранилище больших двоичных объектов.Вместо того, чтобы отправлять ссылки на все это по отдельности, я создаю zip-файл и отправляю эту ссылку пользователям.

Этот процесс выполняется в одном процессе и работает нормально.В последнее время я получаю ошибки исключения OutOfMemory при добавлении файлов в zip-архив, и я изо всех сил пытаюсь найти решение.

Ниже приведен код, который я использую для создания zip-файла (примечание: использование SharpLibZipбиблиотека).В настоящее время происходит сбой с OutOfMemoryException после добавления около 45 файлов по 3,5 МБ на файл (PDF).Ошибка возникает, когда я попадаю в строку: zipStream.PutNextEntry (newEntry).

Кто-нибудь знает, как я могу улучшить этот процесс?Кажется, небольшой файл zip потерпит неудачу на этом уровне.

Using outputMemStream As New MemoryStream()

    Using zipStream As New ICSharpCode.SharpZipLib.Zip.ZipOutputStream(outputMemStream)
          zipStream.SetLevel(7)

          Dim collD3 As UserSurveyReportCollection = GetFileList(RequestID)

          For Each entityD2 As UserSurveyReport In collD3

              Try
                  Dim strF As String = entityD2.FileLocation

                 'Download blob as memorystream and add this stream to the zip file
                 Dim msR As New MemoryStream 
                 msR = objA.DownloadBlobAsMemoryStream(azureAccount, ReportFolder, entityD2.FileName)
                 msR.Seek(0, SeekOrigin.Begin)

                'Determine file name used in zip file archive for item
                 Dim strZipFileName As String = DetermineZipSourceName(entityD2, strFolder, strFileName)

                 'Add MemoryStream to ZipFile Stream
                 Dim newEntry As ICSharpCode.SharpZipLib.Zip.ZipEntry = New ICSharpCode.SharpZipLib.Zip.ZipEntry(strZipFileName)
                 newEntry.DateTime = DateTime.Now

                 zipStream.PutNextEntry(newEntry)
                 msR.CopyTo(zipStream)
                 zipStream.CloseEntry()

                 msR = Nothing
                 zipStream.Flush()

                 intCounter += 1

        End If

    Catch exZip As Exception

    End Try

  Next


    zipStream.IsStreamOwner = False
    zipStream.Finish()
    zipStream.Close()

    outputMemStream.Position = 0

    Dim bytes As Byte() = outputMemStream.ToArray()
    result.Comment = objA.UploadBlob(bytes, azureAccount, ReportFolder, entityReport.FileName).AbsolutePath


    End Using
  End Using

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Для тех, кто занимается C # и хочет записать большой zip-файл в хранилище BLOB-объектов:

var blob = container.GetBlockBlobReference(outputFilename);
using (var stream = await blob.OpenWriteAsync())
using (var zip = new ZipArchive(stream, ZipArchiveMode.Create))
{
    for (int i = 0; i < 2000; i++)
    {
        using (var randomStream = CreateRandomStream(2))
        {
            var entry = zip.CreateEntry($"{i}.zip", CompressionLevel.Optimal);
            using (var innerFile = entry.Open())
            {
                await randomStream.CopyToAsync(innerFile);
            }
        }
    }
}

Это работает на удивление хорошо.Память приложения около 20 Мб с очень низким процессором при потоковой передаче в Azure.Я создал очень большие выходные файлы (> 4,5 ГБ) без проблем

0 голосов
/ 07 июня 2018

Я нашел решение.Этот подход, по-видимому, минимизирует использование памяти при создании zip-файла в памяти и загружает полученный zip-архив в хранилище BLOB-объектов в Azure.При этом используется собственная библиотека System.IO.Compression, а не сторонняя библиотека zip.

Я создал класс с именем ZipModel, который просто имеет имя файла и большой двоичный объект.Я создаю их список и передаю в функцию ниже.Я надеюсь, что это поможет кому-то еще в том же положении.

    Private Function SendBlobsToZipFile(ByVal destinationBlob As CloudBlockBlob, ByVal sourceBlobs As List(Of ZipModel)) As ResultDetail

    Dim result As Boolean = True
    Dim resultCounter as Integer = 0

    Using blobWriteStream As Stream = destinationBlob.OpenWrite()

        Using archive As ZipArchive = New ZipArchive(blobWriteStream, ZipArchiveMode.Create)

            For Each zipM As ZipModel In sourceBlobs
                Try
                    Dim strName As String = String.Format("{0}\{1}", zipM.FolderName, zipM.FileName)
                    Dim archiveEntry As ZipArchiveEntry = archive.CreateEntry(strName, CompressionLevel.Optimal)

                    Using archiveWriteStream As Stream = archiveEntry.Open()
                        zipM.ZipBlob.DownloadToStream(archiveWriteStream)
                        resultCounter  += 1
                    End Using
                Catch ex As Exception

                    result = False

                End Try

            Next

        End Using
    End Using

    Return result


End Function
...