通常,我们可以使用类似的方法从string
中获得byte[]
var result = Encoding.UTF8.GetString(bytes);
但是,我遇到了这个问题:我的输入是IEnumerable<byte[]> bytes
(实现可以是我选择的任何结构)。不能保证字符位于byte[]
之内(例如,一个2字节的UTF8字符的第一个字节可以为bytes [1] [length-1],第二个字节可以为bytes [2] [0] ])。
是否仍然可以在不将所有数组合并/复制在一起的情况下对其进行解码? UTF8是主要重点,但最好是支持其他编码。如果没有其他解决方案,我认为可以实现自己的UTF8阅读。
我计划使用MemoryStream
进行流式传输,但是编码无法在Stream
上运行,而只能在byte[]
上运行。如果合并在一起,则可能的结果数组可能会非常大(List<byte[]>
中已高达4GB)。
我正在使用.NET Standard 2.0。我希望我可以使用2.1(因为它尚未发布)并使用Span<byte[]>
对我的情况来说是完美的!
答案 0 :(得分:2)
Encoding
类不能直接处理它,但是从Decoder
返回的Encoding.GetDecoder()
可以(实际上,这就是它存在的全部原因)。 StreamReader
在内部使用Decoder
。
虽然有点麻烦,但是它需要填充char[]
,而不是返回string
(Encoding.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 :(得分:1)
但是编码只能在字节[]上不能在Stream上工作。
正确,但StreamReader : TextReader
可以链接到流。
因此,只需创建该MemoryStream,在一端插入字节,在另一端使用ReadLine()。我必须说我从未尝试过。
答案 2 :(得分:0)
使用StreamReader
基于Henk的答案的工作代码:
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());
}
}
}