【问题标题】:Zipping a stream on the fly without using the disk在不使用磁盘的情况下即时压缩流
【发布时间】:2018-09-17 21:49:36
【问题描述】:

我正在尝试在我的 C# MVC 项目中编写一个方法,该方法从 S3(或任何地方)流式传输文件,并在将压缩流发送给用户之前将其即时压缩为 zip 文件。到目前为止,我已经找到了几种从流中创建 zip 文件的方法,方法是将其保存到磁盘然后正常返回,但我想跳过保存到磁盘并使用缓冲区流方法。我正在尝试下载一个非常大的文件 (4gb+),该文件很容易压缩到原始大小的一小部分。

到目前为止,我有这个避免磁盘,但似乎首先将整个文件加载到内存中:

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" );
}

一个类似的问题 (Creating a ZIP Archive in Memory Using System.IO.Compression) 只有涉及写入磁盘的答案。

【问题讨论】:

标签: c# amazon-s3 asp.net-mvc-5


【解决方案1】:

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();

【讨论】:

  • 不使用外部库的绝佳解决方案!!效果很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-30
  • 2016-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多