如何有效地编写长度前缀二进制数据

时间:2012-01-12 09:17:08

标签: c# serialization

我将二进制数据格式写入包含序列化对象图的文件。为了更好地适应错误(并且能够调试问题),我正在考虑对流中的每个对象进行长度前缀。我目前正在使用C#和BinaryWriter,但这是一个普遍的问题。

每个对象的大小在完全序列化之前是不可知的,所以能够 写长度前缀有很多策略:

  1. 使用具有足够空间的写缓冲区进行随机访问,并在序列化对象后将长度插入正确的位置。

  2. 将每个对象写入自己的MemoryStream,然后将缓冲区的长度和缓冲区内容写入主流。

  3. 为第一遍中的所有对象写一个零长度,记住文件中所有对象大小的位置(对象大小的表),并填写所有大小的第二遍。

  4. ...

  5. 总尺寸(以及第一个/最外面的物体的尺寸)通常约为1mb,但可以大到50-100mb。我担心的是该过程的性能和内存使用情况。

    哪种策略最有效?

3 个答案:

答案 0 :(得分:0)

  

哪种策略最有效?

确定这一点的唯一方法是衡量。

我的第一直觉是使用#2,但知道这可能会给GC增加压力(或者如果工作流超过80Kb则会碎片化为大对象堆)。然而,#3听起来很有趣,假设跟踪这些位置的复杂性不会影响可维护性。

最后,您需要使用数据进行衡量,并考虑除非您遇到异常情况,否则性能将受网络或存储性能的控制,而不是内存中的处理。

答案 1 :(得分:0)

100MB仅占“小型”服务器(或标准台式计算机)内存的2.5%。我将序列化为内存(例如带有BinaryWriter的byte []数组/ MemoryStream),然后在完成后将其刷新到磁盘。

这也可以让您的代码保持干净,紧凑,易于管理 - 让您免于数小时撕裂头发并在大块地方来回寻找:)

希望这有帮助!

答案 2 :(得分:0)

如果您控制格式,则可以累积对象大小列表并在文件末尾附加目录。但是,不要忘记在.NET世界中,您的写缓冲区在实际传输到磁盘之前会被复制多次。因此,通过避免(比方说)额外的MemoryStream而获得的任何收益都不会提高整体效率。