【发布时间】:2020-01-16 12:43:01
【问题描述】:
我想在二进制平面文件中存储一组时间戳。 我的一个要求是我可以稍后访问各个时间戳以进行高效查询,而不必先读取和反序列化整个数组(我使用二进制搜索算法来查找开始时间戳的文件位置和结束时间戳,这反过来又决定了在这两个时间戳之间读取和反序列化哪些字节,因为整个二进制文件的大小可以达到数 GB)。
显然,简单但缓慢的方法是使用BitConverter.GetBytes(timestamp) 将每个时间戳转换为字节,然后将它们存储在文件中。然后,我可以单独访问文件中的每个项目,并使用我的自定义二进制搜索算法来查找与所需时间戳匹配的时间戳。
但是,我发现 BinaryFormatter 在值类型数组的序列化/反序列化方面非常高效(比 protobuf-net 和我尝试过的任何其他序列化程序快几倍)。因此,我尝试尝试将时间戳数组序列化为二进制形式。但是,显然现在这将阻止我访问文件中的单个时间戳,而无需首先反序列化整个数组。
有没有办法在通过 BinaryFormatter 序列化整个项目数组后仍以二进制形式访问单个项目?
这里有一些代码 sn-p 说明了我的意思:
var sampleArray = new int[5] { 1,2,3,4,5};
var serializedSingleValueArray = sampleArray.SelectMany(x => BitConverter.GetBytes(x)).ToArray();
var serializedArrayofSingleValues = Serializers.BinarySerializeToArray(sampleArray);
var deserializesToCorrectValue = BitConverter.ToInt32(serializedSingleValueArray, 0); //value = 1 (ok)
var wrongDeserialization = BitConverter.ToInt32(serializedArrayofSingleValues, 0); //value = 256 (???)
这里是序列化函数:
public static byte[]BinarySerializeToArray(object toSerialize)
{
using (var stream = new MemoryStream())
{
Formatter.Serialize(stream, toSerialize);
return stream.ToArray();
}
}
编辑:我不需要担心有效的内存消耗或文件大小,因为这些目前还不是瓶颈。序列化和反序列化的速度对我来说是数千兆字节的大型二进制文件以及非常大的原语数组的瓶颈。
【问题讨论】:
-
我不认为通过
BinaryFormatter可以使用它,坦率地说:即使是这样,我仍然无法在我的推荐中找到它BinaryFormatter。这里的数据是什么; 只是时间戳吗?在这种情况下,使用固定大小的有效负载手动编写可能是您的最佳选择;注意:有很多比BitConverter.GetBytes更好的选择 -
特别是:请参阅
BinaryPrimitives下的方法,这些方法提供跨度和原语之间的字节序感知转换 -
@MarcGravell、long[]、double[] 和 decimal[],其中 long[] 是刻度表示中的时间戳。 BinaryFormatter 的序列化和反序列化比我遇到的任何其他序列化器快几个数量级(反序列化比最新版本的 protobuf-net [原始,未配置] 快 20 倍以上。
-
如果有真正的“这可能会更快”,我可能会对使用示例尺寸查看您的场景感兴趣 - 但我想知道切换到固定长度编码是否会有所帮助(
DataFormat) .然而! protobuf still 不是直接为随机访问元素而设计的(除非您使用原始阅读器 API 等) -
@MarcGravell,点了,尽管我怀疑 BinaryPrimitives 总之会超过通过 BinaryFormatter 对整个基元数组的反序列化,尽管我需要对此进行测试。
标签: c# serialization deserialization binaryformatter bitconverter