我一直在尝试在我的一个程序中实现压缩方法。我希望它接收流,压缩它,然后返回压缩流(它返回一个流,因为我希望能够将流传递给另一个函数,而不必将其保存到文件中并稍后重新读取) 。我有一个基于GZipStream的msdn示例的工作测试版本,这是我在尝试将其转换为接收和返回流时的想法:
public static Stream compress(Stream fileToCompress)
{
using (MemoryStream compressedFileStream = new MemoryStream())
{
using (GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress))
{
fileToCompress.CopyTo(compressionStream);
return compressionStream;
}
}
}
将返回的流保存到文件中(在另一种方法中)会导致创建一个0字节的文件(非常有效的压缩,是吗?)。
我尝试过查找other solutions,但我找不到任何使用流的内容,而且我的转换尝试遇到了同样的问题。
编辑:仅仅为了记录,我尝试使用DeflateStream来获得相同的结果。
EDIT2:原来是测试程序无法正常保存。谢谢你的帮助。
答案 0 :(得分:2)
如果您的目标是返回流,则需要不将其放在using
块中。
这样的事情:
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;
}
否则,当流离开using
块时,它会在流上调用Dispose()
。
编辑:此外,在复制之后,流“指针”在最后。您需要将指针设置回开始。保存之前 - 显示在这里。
编辑:删除所有使用块。如果您需要发布流,可以手动执行。
答案 1 :(得分:0)
您可以按照Steven Hansen的建议跳过using
/ Dispose
来电,但使用压缩数据返回MemoryStream
的新副本可能更为清晰。
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());
}
}
如果你想保留单个内存流 - 使用调用删除,不要忘记重新定位流。
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;
请注意,如果文件非常大,使用临时文件来存储压缩/未压缩的流可能会因MemoryStream
中使用的内存分配策略而更快 - 请尝试并测量。