【发布时间】:2016-02-17 11:09:24
【问题描述】:
我在 c# 中使用协议缓冲区 3。我试图通过流弹跳以找到每条消息的起始位置,而实际上没有反序列化消息。所有消息都使用WriteDelimitedTo 写入流。
然后我使用此代码尝试从长度标记跳转:
_map = new List<int>();
_stream.Seek(0, SeekOrigin.Begin);
var codedStream = new CodedInputStream(_stream);
while (_stream.Position < _stream.Length)
{
var length = codedStream.ReadInt32();
_map.Add((int) _stream.Position);
_stream.Seek(length, SeekOrigin.Current);
}
但是,当我执行codedStream.ReadInt32() 时,流位置设置为末尾,而不仅仅是 varint32 之后的下一个字节。
【问题讨论】:
-
什么是
_stream?它包含什么? 是否包含多个整数?此外,网络流通常无法在不先读取所有内容的情况下确定其长度。通过检查.Length而不是 EOF 或Read的结果,您可能正在阅读并丢弃所有内容。这就是为什么大多数 Stream 样本会检查读取的字节数,而不是大小。 -
只是一个内存流。是的,它在单元测试中。我写了 3 条消息并尝试跳过长度前缀。但由于某种原因,CodedInputStream 不只是读取 varin32 的字节,它还寻找基本流到最后。
-
不要尝试操纵底层流,而是使用
CodedInputStream.IsAtEnd。接触底层流是一个坏主意——你已经用另一个包裹了原始流,它可能会缓冲或以其他方式处理它的底层流。查看CodedInputStream的代码,似乎确实如此。 -
我不知道它是否可以方便地在您正在使用的特定库中使用,但绝对有可能以非缓冲方式读取 varint (在不过度阅读的情况下使用数据的想法),然后读取长度限制的流或使用长度限制的阅读器。 - see here(另一半见 L112-L1142);如果这两种方法有用,请随意借用
-
是的,我把你的代码作为解决方案放在了我的脑海里。
标签: c# protocol-buffers