Архивация файлов, находящихся в MemoryStream

244
13 августа 2021, 22:00

На сервере в БД хранятся файлы. Необходимо отправлять эти файлы на почту. Я считываю файлы из БД в MemoryStream. Получается, что я имею несколько MemoryStream потоков, каждый из которых является файлом. Мне необходимо заархивировать эти файлы (потоки), что бы потом отправить этот архив вместе с сообщением на почту. Как правильно упаковывать данные файлы(потоки) в архив и указывать правильное расширение этих файлов в архиве, что бы получатель мог разархивировать и открыть данные файлы?

UPD 0. Я могу перевести MemoryStream'ы в массивы байтов, может их можно как то правильно заархивировать?

Answer 1

Вы можете воспользоваться функционалом класса ZipArchive.

Пусть, например, есть два потока

Stream stream1 = new MemoryStream(Encoding.UTF8.GetBytes("Hello"));
Stream stream2 = new MemoryStream(Encoding.UTF8.GetBytes("World"));

Положить их в архив можно так

using (var fileStream = File.Create("Archive.zip"))
using (var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Create))
{
    var zipEntry = zipArchive.CreateEntry("Hello.txt");
    using (var zeStream = zipEntry.Open())
        stream1.CopyTo(zeStream);
    var zipEntry2 = zipArchive.CreateEntry("World.txt");
    using (var zeStream = zipEntry2.Open())
        stream2.CopyTo(zeStream);
}

В вашем случае, соответственно, будет цикл по потокам.

Если файлы объёмные, то вместо использования MemoryStream целесообразнее может быть протянуть поток напрямую из БД.

Это можно сделать с помощью SqlDataReader. Что-то наподобие

SqlCommand cmd = /* команда для получения данных из БД */;
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
    if (reader.Read())
    {
        int dataFieldIndex = ...;
        using (var dataStream = reader.GetStream(dataFieldIndex))
        {
            var zipEntry = zipArchive.CreateEntry("FileName.ext");
            using (var zeStream = zipEntry.Open())
                dataStream.CopyTo(zeStream);
        }
    }
}

Обратите внимание на модификатор CommandBehavior.SequentialAccess у метода ExecuteReader. При его использовании метод GetStream возвращает SqlSequentialStream (внутренний класс в System.Data.SqlClient), который вычитывает данные пакетами по мере необходимости. Если не использовать SequentialAccess, то метод GetStream будет вычитывать данные полностью и возвращать их обёрнутыми в MemoryStream.

Если бинарные данные в БД лежат в столбце с типом varbinary(max) FILESTREAM, то, вдобавок, можно вытащить их с помощью SqlFileStream.

READ ALSO
реализация tf-idf c#

реализация tf-idf c#

Нужна помощь, пожалуйстаНужно вычислить idf для конкретного текста в richtexbox (tf есть)

238
Сериализация enum в json в виде строки

Сериализация enum в json в виде строки

У меня есть класс со свойством типа enum property и при сериализации в json оно выводится как число, в то время как мне надо чтобы результат был в виде...

189
Ninject, заменить реализацию на другой класс

Ninject, заменить реализацию на другой класс

Знакомлюсь с IoC контейнерами и NinjectПо примерам в сети сделал реализацию для Ninject

345
C# как изменить цвет фигуры

C# как изменить цвет фигуры

Есть форма с кодом:

130