DeflateStream:在阅读时压缩文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DeflateStream:在阅读时压缩文件相关的知识,希望对你有一定的参考价值。

我正试图通过WCF(一些GB)发送大量数据。我想在使用Streams读取文件时压缩文件,但看起来像DeflateStream有两种模式:

  • 压缩(在流上写入)
  • 解压缩(读取流)

在我的情况下,这些模式都不起作用。我想从磁盘读取一个未压缩的文件,并通过WCF返回一个压缩流。

有没有办法这样做,或者我必须使用临时文件(或MemoryStream)?

是缺失的功能还是由于某种原因不可能?

答案

看起来您正在尝试在读取文件时进行压缩。写入deflatestream的方式,压缩必须作为写入的一部分发生。尝试包装您通过网络发送的流,而不是您从磁盘读取的流。如果它们相同,则需要一个中间流。

另一答案

尝试使用这些方法压缩和解压缩字节数组。

    private static byte[] Compress(byte[] data)
    {
        byte[] retVal;
        using (MemoryStream compressedMemoryStream = new MemoryStream())
        {
            DeflateStream compressStream = new DeflateStream(compressedMemoryStream, CompressionMode.Compress, true);
            compressStream.Write(data, 0, data.Length);
            compressStream.Close();
            retVal = new byte[compressedMemoryStream.Length];
            compressedMemoryStream.Position = 0L;
            compressedMemoryStream.Read(retVal, 0, retVal.Length);
            compressedMemoryStream.Close();
            compressStream.Close();
        }
        return retVal;
    }



    private static byte[] Decompress(byte[] data)
    {
        byte[] retVal;
        using (MemoryStream compressedMemoryStream = new MemoryStream())
        {
            compressedMemoryStream.Write(data, 0, data.Length);
            compressedMemoryStream.Position = 0L;
            MemoryStream decompressedMemoryStream = new MemoryStream();
            DeflateStream decompressStream = new DeflateStream(compressedMemoryStream, CompressionMode.Decompress);
            decompressStream.CopyTo(decompressedMemoryStream);
            retVal = new byte[decompressedMemoryStream.Length];
            decompressedMemoryStream.Position = 0L;
            decompressedMemoryStream.Read(retVal, 0, retVal.Length);
            compressedMemoryStream.Close();
            decompressedMemoryStream.Close();
            decompressStream.Close();
        }
        return retVal;
}
另一答案

你应该有类似的东西:

public void CompressData(Stream uncompressedSourceStream, Stream compressedDestinationStream)
{
    using (DeflateStream compressionStream = new DeflateStream(compressedDestinationStream, CompressionMode.Compress))
    {
        uncompressedSourceStream.CopyTo(compressionStream);
    }
}

public void DecompressData(Stream compressedSourceStream, Stream uncompressedDestinationStream)
{
    using (DeflateStream decompressionStream = new DeflateStream(uncompressedDestinationStream, CompressionMode.Decompress))
    {
        compressedSourceStream.CopyTo(decompressionStream);
    }
}

using (FileStream sourceStream = File.OpenRead(@"C:MyDirMyFile.txt))
using (FileStream destinationStream = File.OpenWrite(@"C:MyDirMyCompressedFile.txt.cp"))
{
    CompressData(sourceStream, destinationStream)
}

此外,请注意,您可能必须更改应用程序的.config文件中的WCF设置,以允许传输非常大的内容。

另一答案

您可以将DeflateStream包装在您自己的流中。每次要从压缩流中读取时,都必须将字节输入deflatestream,直到它写入缓冲区。然后,您可以从该缓冲区返回字节。

public class CompressingStream : Stream
{
    private readonly DeflateStream _deflateStream;
    private readonly MemoryStream _buffer;
    private Stream _inputStream;
    private readonly byte[] _fileBuffer = new byte[64 * 1024];

    public CompressingStream(Stream inputStream)
    {
        _inputStream = inputStream;
        _buffer = new MemoryStream();
        _deflateStream = new DeflateStream(_buffer, CompressionMode.Compress, true);
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        while (true)
        {
            var read = _buffer.Read(buffer, offset, count);

            if (read > 0) return read;

            if (_inputStream == null) return 0;

            _buffer.Position = 0;
            read = _inputStream.Read(_fileBuffer, 0, _fileBuffer.Length);
            if (read == 0)
            {
                _inputStream.Close();
                _inputStream = null;
                _deflateStream.Close();
            }
            else
            {
                _deflateStream.Write(_fileBuffer, 0, read);
            }
            _buffer.SetLength(_buffer.Position);
            _buffer.Position = 0;
        }
    }

    public override bool CanRead
    {
        get { return true; }
    }
#region Remaining overrides...
}

每当wcf从流中读取时,压缩流将写入压缩DeflateStream,直到它从输出缓冲区(_buffer)读取为止。这很难看,但它确实有效。

另一答案

我试图创建一个流,每当调用Read时:

  • 从源文件中读取一大块数据
  • 将块写入连接到MemoryStream的DeflateStream
  • MemoryStream的内容复制到Read buffer参数。

当然,由于两个流的大小不相似,因此将更加困难。

最后我解除了这个选项,因为我发现无法预测生成的压缩文件的大小而没有在开始时完全压缩它。

但是,读取文件能够预测文件大小,因此可能有另一种DeflateStream实现。

希望它有助于其他失落的灵魂...

另一答案

Azure API for blobs可替代UploadStream(流)。您可以使用OpenWrite()获取流。因此,现在您可以控制推送字节,因此可以在将内容流式传输到服务时进行压缩

using (var uploadStream = blob.OpenWrite())
using (var deflateStream = new DeflateStream(uploadStream, CompressionMode.Compress))
{
    stream.CopyTo(deflateStream);
}

我没有检查WCF API,但如果你不能这样做,我会感到惊讶。

以上是关于DeflateStream:在阅读时压缩文件的主要内容,如果未能解决你的问题,请参考以下文章

C# 使用压缩流和 Brotli

7z格式压缩[重复]

请问微软.net自带压缩功能是在啥地方啊

Android 安装包优化使用 lib7zr.so 动态库处理压缩文件 ( jni 中 main 函数声明 | 命令行处理 | jni 调用 lib7zr.so 函数库处理压缩文件完整代码 )(代码片

阅读Microsoft Word文档时出现Android Apache POI错误:org.apache.xmlbeans.SchemaTypeLoaderException无法解析句柄的类型(代码片

压缩后的JS代码怎样解压缩?