.NET 6 无法解压缩大型 gzip 文本

Xap*_*ann 17 c# .net-6.0

我必须在 .NET 6 应用程序中解压缩一些 gzip 文本,但是,对于一个 20,627 个字符长的字符串,它只解压缩大约 1/3。我正在使用的代码适用于 .NET 5 或 .NETCore 3.1 中的该字符串以及较小的压缩字符串。

public static string Decompress(this string compressedText)
{
    var gZipBuffer = Convert.FromBase64String(compressedText);
    using var memoryStream = new MemoryStream();
    int dataLength = BitConverter.ToInt32(gZipBuffer, 0);
    memoryStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4);
    var buffer = new byte[dataLength];
    memoryStream.Position = 0;
    using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
    {
        gZipStream.Read(buffer, 0, buffer.Length);
    }
    return Encoding.UTF8.GetString(buffer);
}
Run Code Online (Sandbox Code Playgroud)

结果看起来像这样:

令人惊叹的文本之星...... ...文本在 33,619 之前都很好,之后都是 NULLNULLNULLNULL

33,618 个字符之后的文件其余部分只是空值。

我不知道为什么会发生这种情况。

编辑:当我发现问题不是 Blazor 而实际上是 .NET 6 时,我更新了此内容。我采用了一个在 .NET Core 3.1 中工作的项目,除了编译 .NET 6 之外没有任何更改,并得到了相同的错误。此次更新反映了这一点。

Edit2:刚刚测试过,它可以在 .NET 5 中工作,因此只有 .NET 6 会发生此错误。

Wik*_*hla 23

刚刚确认问题下方评论中链接的文章包含有关该问题的有效线索。

更正后的代码为:

string Decompress(string compressedText)
{
    var gZipBuffer = Convert.FromBase64String(compressedText);

    using var memoryStream = new MemoryStream();
    int dataLength = BitConverter.ToInt32(gZipBuffer, 0);
    memoryStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4);

    var buffer = new byte[dataLength];
    memoryStream.Position = 0;

    using var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress);

    int totalRead = 0;
    while (totalRead < buffer.Length)
    {
        int bytesRead = gZipStream.Read(buffer, totalRead, buffer.Length - totalRead);
        if (bytesRead == 0) break;
        totalRead += bytesRead;
    }

    return Encoding.UTF8.GetString(buffer);
}
Run Code Online (Sandbox Code Playgroud)

这种方法改变了

gZipStream.Read(buffer, 0, buffer.Length);
Run Code Online (Sandbox Code Playgroud)

    int totalRead = 0;
    while (totalRead < buffer.Length)
    {
        int bytesRead = gZipStream.Read(buffer, totalRead, buffer.Length - totalRead);
        if (bytesRead == 0) break;
        totalRead += bytesRead;
    }
Run Code Online (Sandbox Code Playgroud)

Read正确考虑了 的返回值。

如果不进行更改,该问题很容易在任何足以生成长度 > ~10kb 的 gzip 的随机字符串上重复出现。

这是压缩器,如果有人有兴趣自己测试一下

string Compress(string plainText)
{
    var buffer = Encoding.UTF8.GetBytes(plainText);
    using var memoryStream = new MemoryStream();

    var lengthBytes = BitConverter.GetBytes((int)buffer.Length);
    memoryStream.Write(lengthBytes, 0, lengthBytes.Length);

    using var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress);
    
    gZipStream.Write(buffer, 0, buffer.Length);
    gZipStream.Flush();

    var gZipBuffer = memoryStream.ToArray();

    return Convert.ToBase64String(gZipBuffer);
}
Run Code Online (Sandbox Code Playgroud)