解压缩的GZPRIPPPRECT READONLYMEMORY< byte>在我做jsondocument.parse之前

发布于 2025-02-13 23:14:53 字数 1315 浏览 4 评论 0 原文

WebSocket客户端正在返回 readonlymemory< byte>

问题是 jsondocument.parse 由于已压缩缓冲区而失败。在解析之前,我必须以某种方式对其进行解压缩。我该怎么做?我无法真正更改Websocket库代码。

我想要的是 public func< readonlymemory< byte>> datainterPreterBytes =()=> 可选地将这些字节解压缩在此类中。我该怎么做?是否可以解压缩 readonlyMemory< ,并且如果处理程序未使用,则基本上什么都不做。

private static string DecompressData(byte[] byteData)
{
    using var decompressedStream = new MemoryStream();
    using var compressedStream = new MemoryStream(byteData);
    using var deflateStream = new GZipStream(compressedStream, CompressionMode.Decompress);
    deflateStream.CopyTo(decompressedStream);
    decompressedStream.Position = 0;

    using var streamReader = new StreamReader(decompressedStream);
    return streamReader.ReadToEnd();
}

片段

private void OnMessageReceived(object? sender, MessageReceivedEventArgs e)
{
    var timestamp = DateTime.UtcNow;

    _logger.LogTrace("Message was received. {Message}", Encoding.UTF8.GetString(e.Message.Buffer.Span));

    // We dispose that object later on
    using var document = JsonDocument.Parse(e.Message.Buffer);
    var tokenData = document.RootElement;

The websocket client is returning a ReadOnlyMemory<byte>.

The issue is that JsonDocument.Parse fails due to the fact that the buffer has been compressed. I've got to decompress it somehow before I parse it. How do I do that? I cannot really change the websocket library code.

What I want is something like public Func<ReadOnlyMemory<byte>> DataInterpreterBytes = () => which optionally decompresses these bytes out of this class. How do I do that? Is it possible to decompress ReadOnlyMemory<byte> and if the handler is unused to basically to do nothing.

private static string DecompressData(byte[] byteData)
{
    using var decompressedStream = new MemoryStream();
    using var compressedStream = new MemoryStream(byteData);
    using var deflateStream = new GZipStream(compressedStream, CompressionMode.Decompress);
    deflateStream.CopyTo(decompressedStream);
    decompressedStream.Position = 0;

    using var streamReader = new StreamReader(decompressedStream);
    return streamReader.ReadToEnd();
}

Snippet

private void OnMessageReceived(object? sender, MessageReceivedEventArgs e)
{
    var timestamp = DateTime.UtcNow;

    _logger.LogTrace("Message was received. {Message}", Encoding.UTF8.GetString(e.Message.Buffer.Span));

    // We dispose that object later on
    using var document = JsonDocument.Parse(e.Message.Buffer);
    var tokenData = document.RootElement;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

月野兔 2025-02-20 23:14:53

因此,如果您有一个字节数组,则将执行此操作:

private static JsonDocument DecompressData(byte[] byteData)
{
    using var compressedStream = new MemoryStream(byteData);
    using var deflateStream = new GZipStream(compressedStream, CompressionMode.Decompress);
    return JsonDocument.Parse(deflateStream);
}

这类似于上面的摘要,但不需要中间副本:只需直接从 gzipstream 中读取即可。 jsondocument.parse 还具有一个接管流的过载,因此您可以使用它并避免另一个无用的副本。

不幸的是,您没有字节数组,您有一个 readonlymemory&lt; byte&gt; 。没有办法从 readonlymemory&lt; byte&gt; 中创建内存流。老实说,感觉就像是一种监督,就像他们忘了将该功能放入.NET中。

因此,这是您的选择。

第一个选项是只需转换 readonlyMemory&lt; byte&gt; 对象与 toArray()>:

// assuming e.Message.Buffer is a ReadOnlyMemory<byte>
using var document = DecompressData(e.Message.Buffer.ToArray());

这确实很简单,但请记住它实际上复制了数据,因此适用于数据,因此大型文档,如果您想避免使用过多的内存,那可能不是一个好主意。

第二个是尝试从内存中提取基础数组。这可以通过 MemoryMarshal.trygetArray 来实现,它为您提供 arrayseggentemenseggenseggenseggensegensegensegensegensegensegensegensegensegray (但是,如果内存实际上不是托管数组)。

private static JsonDocument DecompressData(ReadOnlyMemory<byte> byteData)
{
    if(MemoryMarshal.TryGetArray(byteData, out var segment))
    {
        using var compressedStream = new MemoryStream(segment.Array, segment.Offset, segment.Count);
        // rest of the code goes here
    }
    else
    {
        // Welp, this memory isn't actually an array, so... tough luck?
    } 
}

第三种方式可能会感到肮脏,但是如果您可以使用不安全的代码,可以固定内存的跨度,然后使用 unmanagedMemorystream

private static unsafe JsonDocument DecompressData(ReadOnlyMemory<byte> byteData)
{
    fixed (byte* ptr = byteData.Span)
    {
        using var compressedStream = new UnmanagedMemoryStream(ptr, byteData.Length);
        using var deflateStream = new GZipStream(compressedStream, CompressionMode.Decompress);
        return JsonDocument.Parse(deflateStream);
    }       
}

另一个解决方案是编写您自己的 stream < /代码>支持此的类。 包装器 目的。如果您不为此使用整个第三方库,那么您可能只能滚动自己的代码太多。

So, if you had a byte array, you'd do this:

private static JsonDocument DecompressData(byte[] byteData)
{
    using var compressedStream = new MemoryStream(byteData);
    using var deflateStream = new GZipStream(compressedStream, CompressionMode.Decompress);
    return JsonDocument.Parse(deflateStream);
}

This is similar to your snippet above, but no need for the intermediate copy: just read straight from the GzipStream. JsonDocument.Parse also has an overload that takes a stream, so you can use that and avoid yet another useless copy.

Unfortunately, you don't have a byte array, you have a ReadOnlyMemory<byte>. There is no way out of the box to create a memory stream out of a ReadOnlyMemory<byte>. Honestly, it feels like an oversight, like they forgot to put that feature into .NET.

So here are your options instead.

The first option is to just convert the ReadOnlyMemory<byte> object to an array with ToArray():

// assuming e.Message.Buffer is a ReadOnlyMemory<byte>
using var document = DecompressData(e.Message.Buffer.ToArray());

This is really straightforward, but remember it actually copies the data, so for large documents it might not be a good idea if you want to avoid using too much memory.

The second is to try and extract the underlying array from the memory. This can be achieved with MemoryMarshal.TryGetArray, which gives you an ArraySegment (but might fail if the memory isn't actually a managed array).

private static JsonDocument DecompressData(ReadOnlyMemory<byte> byteData)
{
    if(MemoryMarshal.TryGetArray(byteData, out var segment))
    {
        using var compressedStream = new MemoryStream(segment.Array, segment.Offset, segment.Count);
        // rest of the code goes here
    }
    else
    {
        // Welp, this memory isn't actually an array, so... tough luck?
    } 
}

The third way might feel dirty, but if you're okay with using unsafe code, you can just pin the memory's span and then use UnmanagedMemoryStream:

private static unsafe JsonDocument DecompressData(ReadOnlyMemory<byte> byteData)
{
    fixed (byte* ptr = byteData.Span)
    {
        using var compressedStream = new UnmanagedMemoryStream(ptr, byteData.Length);
        using var deflateStream = new GZipStream(compressedStream, CompressionMode.Decompress);
        return JsonDocument.Parse(deflateStream);
    }       
}

The other solution is to write your own Stream class that supports this. The Windows Community Toolkit has an extension method that returns a Stream wrapper around the memory object. If you're not okay with using an entire third party library just for that, you can probably just roll your own, it's not that much code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文