问题
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