【问题标题】:How to best read and UTF-8-decode byte buffers?如何最好地读取和 UTF-8 解码字节缓冲区?
【发布时间】:2011-08-25 07:51:27
【问题描述】:

我有一个Stream,它产生UTF-8 编码字符串。这些字符串代表我需要解析的 XML 文档。流是从TcpClient 获取的。

假设我将流读入大小为 64 的缓冲区(我知道有点小)。将这些 64 字节缓冲区直接传递给字符串解码步骤可能会失败,因为某些 UTF-8 编码字符可能会沿 64 字节边界拆分。缓冲区可能以字符的前两个字节结束,下一个缓冲区包含该字符的最后一个字节。

我现在要做的是连接缓冲区,直到我执行的读取没有读取完整的 64 个字节,这表明我已经读取到某个内容的末尾(在我的例子中,是一个 XML 文档)。但是,有时,我阅读的 XML 文档恰好在 64 字节边界处结束。在这种情况下,我不知道我可以将字节数组传递给解码步骤(我需要等待下一个文档)。

我意识到我可以通过增加缓冲区大小来降低机会。然而,它发生的机会总是很小。我还可以增加缓冲区大小,以便我遇到的任何 XML 文档都适合,但我只是想知道是否有另一种解决方案,以某种方式从字节流中检测字符边界所在的位置。

【问题讨论】:

    标签: c# encoding utf-8 stream


    【解决方案1】:

    您对问题和陷阱的看法是正确的。

    解决方案已经存在:将StreamReader 包裹在您的流周围并使用Read()ReadLine()

    如果您确实想要 DIY 解决方案,则必须查看编码器状态属性。超出我的能力。

    【讨论】:

    • 看起来StreamReader 完全符合我的要求。我记得看过那门课,但我不记得为什么我放弃了它。不能使用ReadLine(),因为没有换行符,它是一个连续的 XML 文档流。
    • Encoder 状态属性是什么意思?我知道 EncoderDecoder 类,但不确定您指的是什么状态属性。
    • @Ronald 不要忽视 XmlReader。这些状态属性在相关的编码器/编码类中,忘记是哪个。
    • XmlReader 不起作用。我得到一个连续的 XML 文档流,并且无法让 XmlReader 接受多个文档作为输入(因为这将是无效的 XML)。
    • XmlReader 是一个拉解析器(它从流中拉取数据)。找到一个推送解析器,然后您可以在收到 TCP 块时将它们推送到解析器中。由于 TCP 数据有多个文档,因此可以先将自定义的开始标签推送到解析器中,然后依次开始推送文档,它们将被视为二级开始标签,而不是顶级文档。跨度>
    【解决方案2】:

    我相信您的方法在理论上存在缺陷,即使它在实践中应该始终正确工作:不能保证成功读取小于(缓冲区大小)就表明已完整接收 XML 文档。 TCP 堆栈完全有权一次将文档返回给您一个字节。将缓冲区大小增加到几 KB 应该会导致此问题出现。

    正确解决上述缺陷也将解决您当前的问题:在 TCP 流中的每个 XML 文档之前添加某种包含以下文档长度的固定长度标头(例如 8 个字节)。您将始终知道何时阅读了完整的标题(因为它是固定大小的),并且当您收到整个文档时,您将知道标题。

    【讨论】:

    • 嗯,你是对的,这是一种有缺陷的方法,但没有意识到它可能会出错(尽管在实践中它可能总是有效)。不幸的是,我对发送方没有影响。否则,标题将是一个很好的解决方案,既可以解决我最初的问题,也可以作为 XML 文档之间的边界。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多