二进制格式化程序,将位置设置为反序列化特定对象

本文关键字:反序列化 对象 设置 位置 格式化 程序 二进制 | 更新日期: 2023-09-27 18:28:42

我想问一下关于使用二进制格式化程序序列化/反序列化对象的问题。我正在尝试反序列化FileStream中的对象,该对象包含许多已逐一序列化的对象。对象的大小太大,无法保存在进程内存中,这就是为什么我不将所有对象打包在一个文件中,例如:列表,因为它们在进程内存太大,所以我多次序列化所需的数量。通过这种方式,它不会占用很多进程内存,因为我只是交替处理一个对象,而不是所有对象。看看草图,我指的是

<FileStream>
----Object 1-----Size = 100 Mb------index = 0
----Object 2-----Size = 100 Mb------index = 1
----Object 3-----Size = 100 Mb------index = 2
----Object 4-----Size = 100 Mb------index = 3
----Object 5-----Size = 100 Mb------index = 4
----Object 6-----Size = 100 Mb------index = 5
</FileStream>

序列化对象也成功了,现在我遇到了反序列化对象的问题。问题是:在列表中,我们可以使用带索引的项目。所以如果我们想取第五个指数,我们可以称之为:

    List<object> list = new List<object>();
    list(0) = "object1";
    list(1) = "object2";
    list(2) = "object3";
    list(3) = "object4";
    list(4) = "object5";
    list(5) = "object6";
    object fifthIndex = list[5]; // here we can get item based index

现在的问题是,我如何获得具有第五个索引的对象,就像使用二进制格式化程序在文件流中的六个反序列化对象上的列表方法一样。我知道在FileStream中有一个名为"FileStream.Position"的属性,但它不像Index,当我对对象进行反序列化/序列化时,它看起来像一个随机数。也许它会增加随机数。

事实上,我已经成功了,但我敢打赌这不是最好的方式来看看我的代码,我曾经尝试过:

object GetObjectStream(FileStream fs, int index)
{
    if (fs != null)
    {
        BinaryFormatter binaryformatter = new BinaryFormatter();
        bool isFinished = false; int count = 0;
        while (isFinished == false)
        {
            try
            {
                object objectdeserialized = binaryformatter.Deserialize(fs);
                if (count == index) return objectdeserialized;
                count++;
            }
            catch
            {
                isFinished = true;
                return null;
            }
        }
    }
    return null;
}

这些代码将"foreach"已序列化的每个对象,然后反序列化每个对象。我打赌我的代码不是最好的方法,因为要反序列化包含100MB的对象可能需要很长时间,我甚至不知道除了被反序列化的索引之外的对象是否会被处理?我想要类似"序列化跳跃"的方法。

如果我们能解决这个问题,你的回答对我很有帮助。

谢谢。。

二进制格式化程序,将位置设置为反序列化特定对象

每个对象很可能会占用不同的空间来序列化数据包,尤其是对于字符串和数组之类的对象。基本上,为了有效地(即不需要每次都完整地读取每个对象),您需要:

  • 通过将每个对象序列化为MemoryStream,存储.Length(任何方便的方式;一个4字节的小字节序块就足够了),将它所占用的数据量作为每个对象的前缀,然后将写入MemoryStream的数据复制到输出中;然后可以跳过n次到第n项-(将4个字节作为int读取,跳过那么多字节)
  • 在一个单独的索引中,在序列化每个对象之前存储基本流的.Position;然后要读取第n个对象,您可以使用索引找到所需的位置,然后滚动到那里

事实上,你在这里很幸运:BinaryFormatter实际上并没有被记录为可以安全附加,但碰巧它确实有点成功了,好吧,你这样做了——但并非所有序列化格式都是这样。

不过,就我个人而言,我会质疑是否有一种不同的设计可以在这里使用。

----Write objects to file---
1. Keep a Dictionary<KeyType, long> dict.  KeyType probably int if you key on an object number. 
2. open file FileX for output; FileX.position = 0 at this point.
3. For each object: 
         update dictionary(oject.key, fileX.Position)
         Serialize object to FileX (note: FileX.Position is updated by BinaryFormatter)
4. Close FileX. Save Dictionary (serialize to another file).
----Read Back Object---
Use Dictionary to get offset based on key of object you want:
     do FileX.Seek(offset, 0); formatter.deserialize(FileX) to get back the
object you wish.