Compression Streams

∥☆過路亽.° 提交于 2019-12-25 02:45:00

问题


I've been trying to implement a compression method in one of my programs. I want it to take in a stream, compress it, and return the compressed stream (It returns a stream because I want to be able to pass the stream to another function without having to save it to a file and re-read it later). I had a working test version based on the msdn example for GZipStream, and this is what I came up with when I tried to convert it to taking in and returning streams:

public static Stream compress(Stream fileToCompress)
{
    using (MemoryStream compressedFileStream = new MemoryStream())
    {
        using (GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress))
        {
            fileToCompress.CopyTo(compressionStream);
            return compressionStream;
        }
    }
}

Saving the returned stream to a file (in another method) results in a file of 0 bytes being created (pretty efficient compression, huh?).

I've tried looking for other solutions, but I haven't been able to find any that use streams, and my attempts to convert run into the same problem.

Edit: Just for the record, I have tried using DeflateStream to the same results.

EDIT2: Turns out it was the test program not saving properly. Thanks for the help.


回答1:


If your goal is to return the stream, you need to not put it in the using block.

Something like this:

public static Stream compress(Stream fileToCompress) {
    MemoryStream compressedFileStream = new MemoryStream();
    GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress);
    fileToCompress.CopyTo(compressionStream);
    compressionStream.Seek(0, SeekOrigin.Begin); // Reset to stream start.
    return compressionStream;
}

Otherwise, when the stream leaves the using block, it calls Dispose() on the stream.

EDIT: Also, after a copy, the stream "pointer" is at the end. You need to set the pointer back to the start. Before you save - shown here.

EDIT: Removed all using blocks. If you need to release a stream, you can do it manually.




回答2:


You can skip using/Dispose calls as suggested by Steven Hansen, but it may be cleaner to return new copy of MemoryStream with compressed data.

public static Stream compress(Stream fileToCompress)
{
    using (MemoryStream compressedFileStream = new MemoryStream())
    {
        using (var compressionStream = new GZipStream(
             compressedFileStream, CompressionMode.Compress))
        {
            fileToCompress.CopyTo(compressionStream);
        }
        return new MemoryStream(compressionStream.ToArray());
    }
}

If you want to keep just single memory stream - remove using calls and don't forget to reposition the stream.

var compressedFileStream = new MemoryStream();
var compressionStream = new GZipStream(
           compressedFileStream, CompressionMode.Compress);
fileToCompress.CopyTo(compressionStream);
 // Flush to make sure all data written by compression stream.
compressionStream.Flush();
compressedFileStream.Position = 0;
return compressedFileStream;

Note that if you file is very large using temporary file to store compressed/uncompressed stream may be faster due to memory allocation strategy used in MemoryStream - try both and measure.



来源:https://stackoverflow.com/questions/22086085/compression-streams

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!