【问题标题】:Compression Streams压缩流
【发布时间】:2014-03-31 22:04:01
【问题描述】:

我一直在尝试在我的一个程序中实现一种压缩方法。我希望它接收一个流,压缩它,然后返回压缩流(它返回一个流,因为我希望能够将流传递给另一个函数,而不必将其保存到文件并稍后重新读取) .我有一个基于 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 字节的文件(非常有效的压缩,对吧?)。

我试过寻找othersolutions,但我找不到任何使用流的东西,我尝试转换也遇到了同样的问题。

编辑:为了记录,我尝试使用 DeflateStream 来获得相同的结果。

EDIT2:原来是测试程序没有正确保存。感谢您的帮助。

【问题讨论】:

    标签: c# stream compression


    【解决方案1】:

    如果您的目标是返回流,则需要将其放入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()

    编辑:另外,在复制之后,流“指针”位于末尾。您需要将指针设置回起点。保存之前 - 此处显示。

    编辑:删除所有 using 块。如果需要放流,可以手动放。

    【讨论】:

    • 请注意,您的示例实际上关闭了底层流,这将导致相同的“读取/写入已处理流”异常。
    • 我不能 100% 确定 MemoryStreamGZipStream 的交互,所以我相信你的话。我的编辑删除了使用。
    • 感谢您的快速回复。我想我以前尝试过,但没有奏效。我再次尝试以确保,但我仍然遇到问题。还有@AlexeiLevenkov,它没有抛出任何异常,它只是返回一个空流。
    • @user3299958 - 我把应该在我的帖子中工作的示例。请务必阅读此搜索中的答案 stackoverflow.com/search?q=[c%23]+memorystream+zero+position 涵盖您的 0 字节文件问题。
    • 我编辑显示寻找Stream开始的代码。在您保存之前需要这样做。
    【解决方案2】:

    您可以按照 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 中使用的内存分配策略,使用临时文件存储压缩/未压缩流可能会更快 - 尝试两者并测量。

    【讨论】:

      猜你喜欢
      • 2021-01-19
      • 2011-04-19
      • 2013-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-13
      • 1970-01-01
      • 2017-01-17
      相关资源
      最近更新 更多