简体   繁体   English

C# GZipStream 压缩数据但解压返回空 stream

[英]C# GZipStream compressing data but decompression returns empty stream

I have the following code:我有以下代码:

    public static async Task<string> Compress(string inputString)
    {
        var bytes = Encoding.Unicode.GetBytes(inputString);
        await using var input = new MemoryStream(bytes);
        await using var output = new MemoryStream();
        await using var stream = new GZipStream(output, CompressionLevel.SmallestSize);

        await input.CopyToAsync(stream);

        return Convert.ToBase64String(output.ToArray());
    }

    public static async Task<string> Decompress(string inputString)
    {
        var bytes = Convert.FromBase64String(inputString);

        await using var output = new MemoryStream();
        await using var input = new MemoryStream(bytes);
        await using var stream = new GZipStream(input, CompressionMode.Decompress);

        await stream.CopyToAsync(output);
        await stream.FlushAsync();
        
        return Encoding.Unicode.GetString(output.ToArray());
    }

When I try to compress the string 'Hello World', the compressed Base64 encoded string is 'H4sIAAAAAAACCg=='当我尝试压缩字符串“Hello World”时,压缩后的 Base64 编码字符串为“H4sIAAAAAAAACCg==”

When I try to decompress the Base64 encoded string 'H4sIAAAAAAACCg==' the method Decompress returns an empty string.当我尝试解压缩 Base64 编码字符串 'H4sIAAAAAAAACCg==' 时,方法 Decompress 返回一个空字符串。

You are not getting the correct compressed string.您没有得到正确的压缩字符串。 output.ToArray() is being called before stream GZipStream is flushed, so the contents of output MemoryStream would not be the full compressed bytes yet. output.ToArray()stream GZipStream被刷新之前被调用,所以output MemoryStream的内容还不是完整的压缩字节。 You need to add await stream.FlushAsync();您需要添加await stream.FlushAsync(); after await input.CopyToAsync(stream);等待后await input.CopyToAsync(stream); . .

The GZipStream respectively its internal DeflateStream is designed to implicitly flush its internal buffer on a call to Dispose (see https://github.com/dotnet/runtime/blob/main/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateZLib/DeflateStream.cs ). GZipStream分别其内部DeflateStream旨在在调用Dispose时隐式刷新其内部缓冲区(请参阅https://github.com/dotnet/runtime/blob/main/src/libraries/System.IO.Compression/src/System /IO/Compression/DeflateZLib/DeflateStream.cs )。

For using statements without curly braces, which have been introduced with C# 8.0, the scope is limited by the containing scope.对于使用 C# 8.0 引入的不带花括号的语句,scope 受到包含 scope 的限制。 In this case, the containing scope is the method itself, which means that the object goes out of scope when the method finally exits.在这种情况下,包含 scope 是方法本身,这意味着当方法最终退出时,object 会从 scope 中退出。 Therefore, the implicit flush from stream to output happens after Convert.ToBase64String(output.ToArray()) .因此,从streamoutput的隐式刷新发生在Convert.ToBase64String(output.ToArray())之后。

To avoid this, we can add curly braces to limit the scope (see example below), or by flushing the stream explicitly (this is not valid for all .NET versions, see https://github.com/dotnet/runtime/commit/728aa671567d498c1acb6e13cb5cf4f7a883acf7 . To avoid this, we can add curly braces to limit the scope (see example below), or by flushing the stream explicitly (this is not valid for all .NET versions, see https://github.com/dotnet/runtime/commit/ 728aa671567d498c1acb6e13cb5cf4f7a883acf7

public static async Task<string> Compress(string inputString)
{
    var bytes = Encoding.Unicode.GetBytes(inputString);
    
    await using (var input = new MemoryStream(bytes))
    {
        await using (var output = new MemoryStream())
        {
            await using (var stream = new GZipStream(output, CompressionLevel.SmallestSize))
            {
                await input.CopyToAsync(stream);
            }
        
            return Convert.ToBase64String(output.ToArray());
        }
    }
}

public static async Task<string> Decompress(string inputString)
{
    var bytes = Convert.FromBase64String(inputString);

    await using (var output = new MemoryStream())
    {
        await using (var input = new MemoryStream(bytes))
        {
            await using (var stream = new GZipStream(input, CompressionMode.Decompress))
            {
                await stream.CopyToAsync(output);
            }
        }

        return Encoding.Unicode.GetString(output.ToArray());
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM