Encoding API可以解码流/非连续字节吗?

问题描述 投票:0回答:3

通常我们可以使用类似的东西从string获得byte[]

var result = Encoding.UTF8.GetString(bytes);

但是,我遇到了这个问题:我的输入是IEnumerable<byte[]> bytes(实现可以是我选择的任何结构)。不保证字符在byte[]内(例如,一个2字节的UTF8字符可以在字节[1] [长度为1]中具有其第一个字节,在字节[2] [0]中具有其第二个字节)。

无论如何解码它们而不将所有阵列合并/复制在一起? UTF8是主要关注点,但如果可以支持其他编码则更好。如果没有其他解决方案,我认为实现我自己的UTF8读数就是这样。

我计划使用MemoryStream流式传输它们,但是编码无法在Stream上工作,只需byte[]。如果合并在一起,潜在的结果数组可能非常大(已经在List<byte[]>中高达4GB)。

我使用的是.NET Standard 2.0。我希望我能使用2.1(因为它尚未发布)并使用Span<byte[]>,对我的情况来说是完美的!

c# character-encoding .net-standard
3个回答
2
投票

Encoding类不能直接处理,但Decoder返回的Encoding.GetDecoder()可以(事实上,这是它存在的全部原因)。 StreamReader内部使用Decoder

虽然它有点繁琐,因为它需要填充char[],而不是返回stringEncoding.GetString()StreamReader通常处理填充char[]的业务)。

使用MemoryStream的问题在于,您将所有字节从一个数组复制到另一个数组,因为没有增益。如果所有缓冲区的长度都相同,则可以执行以下操作:

var decoder = Encoding.UTF8.GetDecoder();
// +1 in case it includes a work-in-progress char from the previous buffer
char[] chars = decoder.GetMaxCharCount(bufferSize) + 1;
foreach (var byteSegment in bytes)
{
    int numChars = decoder.GetChars(byteSegment, 0, byteSegment.Length, chars, 0);
    Debug.WriteLine(new string(chars, 0, numChars));
}

如果缓冲区长度不同:

var decoder = Encoding.UTF8.GetDecoder();
char[] chars = Array.Empty<char>();
foreach (var byteSegment in bytes)
{
    // +1 in case it includes a work-in-progress char from the previous buffer
    int charsMinSize = decoder.GetMaxCharCount(bufferSize) + 1;
    if (chars.Length < charsMinSize)
        chars = new char[charsMinSize];
    int numChars = decoder.GetChars(byteSegment, 0, byteSegment.Length, chars, 0);
    Debug.WriteLine(new string(chars, 0, numChars));
}

1
投票

但是编码不能在Stream上工作,只有byte []。

正确,但StreamReader : TextReader可以链接到流。

因此,只需创建MemoryStream,在一端推入字节,在另一端使用ReadLine()。我必须说我从未尝试过。


0
投票

基于Henk使用StreamReader的答案的工作代码:

    using (var memoryStream = new MemoryStream())
    {
        using (var reader = new StreamReader(memoryStream))
        {
            foreach (var byteSegment in bytes)
            {
                memoryStream.Seek(0, SeekOrigin.Begin);
                await memoryStream.WriteAsync(byteSegment, 0, byteSegment.Length);
                memoryStream.Seek(0, SeekOrigin.Begin);

                Debug.WriteLine(await reader.ReadToEndAsync());
            }
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.