Архивирование потока на лету без использования диска - PullRequest
0 голосов
/ 18 сентября 2018

Я пытаюсь написать метод в своем проекте C # MVC, который передает файл из S3 (или из любого места) и сжимает его в zip-файл на лету перед отправкой сжатого потока пользователю. До сих пор я нашел несколько способов создать zip-файл из потока, сохранив его на диск и затем вернув его в обычном режиме, но я бы хотел пропустить сохранение на диск и использовать буфер для потоковой передачи. Я пытаюсь загрузить очень большой файл (4 ГБ +), который легко сжимается до доли исходного размера.

Пока у меня есть это, которое избегает диска, но, кажется, сначала загружает весь файл в память:

using( var memoryStream = new MemoryStream() )
{
    using( var archive = new ZipArchive( memoryStream, ZipArchiveMode.Create, true ) )
    {
        var zipEntry = archive.CreateEntry( File );

        using( var entryStream = zipEntry.Open() )
        {
            S3.StreamFile( File, Bucket ).CopyTo( entryStream );
        }
    }

    return base.File( memoryStream.ToArray(), "application/zip", File + ".zip" );
}

Аналогичный вопрос ( Создание ZIP-архива в памяти с помощью System.IO.Compression ) содержит ответы только на запись на диск.

1 Ответ

0 голосов
/ 18 сентября 2018

Класс ZipArchive требует потока, который предоставляет текущую позицию.Класс TrackablePositionStream ниже сохраняет позицию, увеличивая поле при вызове записи

public class TrackablePositionStream : Stream
{
    private readonly Stream _stream;

    private long _position = 0;

    public TrackablePositionStream(Stream stream)
    {
        this._stream = stream;
    }

    public override void Flush()
    {
        this._stream.Flush();
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        throw new NotImplementedException();
    }

    public override void SetLength(long value)
    {
        throw new NotImplementedException();
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        throw new NotImplementedException();
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        this._position += count;
        this._stream.Write(buffer, offset, count);
    }

    public override bool CanRead => this._stream.CanRead;

    public override bool CanSeek => this._stream.CanSeek;

    public override bool CanWrite => this._stream.CanWrite;

    public override long Length => this._stream.Length;

    public override long Position
    {
        get
        {
            return this._position;
        }
        set
        {
            throw new NotImplementedException();
        }
    }
}

Затем используйте его в своем методе действия:

using( var archive = new ZipArchive(new TrackablePositionStream(response.OutputStream), ZipArchiveMode.Create, true ) )
{
    var zipEntry = archive.CreateEntry( File );

    using(var entryStream = zipEntry.Open() )
    {
        S3.StreamFile( File, Bucket ).CopyTo( entryStream );
    }
}

return new EmptyResult();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...