GZipStream 在写入 FileStream 时有效,但不适用于 MemoryStream

GZipStream works when writing to FileStream, but not MemoryStream

如果压缩一些 json 文本,并使用 FileStream 将其写入文件,我会得到预期的结果。但是,我不想写入磁盘。我只是想存储压缩数据的内存流。

压缩到 FileStream

string json = Resource1.json;

using (MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes(json)))
using (FileStream output = File.Create(@"C:\Users\roarker\Desktop\output.json.gz"))
{
    using (GZipStream compression = new GZipStream(output, CompressionMode.Compress))
    {
        input.CopyTo(compression);
    }
}

以上有效。下面,输出内存流的长度为 10,结果是一个空的 .gz 文件。

string json = Resource1.json;

using (MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes(json)))
using (MemoryStream output = new MemoryStream())
{
    using (GZipStream compression = new GZipStream(output, CompressionMode.Compress))
    {
        input.CopyTo(compression);

        byte[] bytes = output.ToArray();
    }
}

编辑:output.ToArray() 移到内部 using 子句之外似乎可行。但是,这会关闭大多数用法的输出流。即:

        using (MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes(json)))
        using (MemoryStream output = new MemoryStream())
        {
            using (GZipStream compression = new GZipStream(output, CompressionMode.Compress))
            {
                input.CopyTo(compression);
            }
            WriteToFile(output);
        }

其中:

    public static void WriteToFile(Stream stream)
    {
        using (FileStream output = File.Create(@"C:\Users\roarker\Desktop\output.json.gz"))
        {
            stream.CopyTo(output);
        }
    }

这将在 stream.CopyTo 上失败,因为流已关闭。我知道我可以从 output.ToArray() 的字节创建一个新的 Stream,但为什么这是必要的?为什么 ToArray() 在流关闭时工作?

最终编辑:

只需要使用 GZipStream 的构造函数和 leaveOpen 参数。

您在关闭 GZipStream 之前调用 ToArray()... 这意味着它还没有机会刷新其缓冲区的最后几位。这是压缩加密流的常见问题,关闭流需要写入一些最终数据。 (例如,即使显式调用 Flush() 也无济于事。)

只需移动 ToArray 调用:

using (MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes(json)))
using (MemoryStream output = new MemoryStream())
{
    using (GZipStream compression = new GZipStream(output, CompressionMode.Compress))
    {
        input.CopyTo(compression);
    }
    byte[] bytes = output.ToArray();
    // Use bytes
}

(请注意,当您调用 ToArray 时,流将被释放,但没关系。)