从要显示的文件中反序列化对象列表

Posted

技术标签:

【中文标题】从要显示的文件中反序列化对象列表【英文标题】:Deserialize list of objects from a file to be displayed 【发布时间】:2015-11-15 20:48:33 【问题描述】:

基本上,我创建了一个文件,用于存储来自名为 TravelRecord 的对象的序列化数据。我使用 BinaryFormatter() 序列化数据并将其存储在文件中没有问题,检索第一条记录也没有问题。我只想检索所有记录并将它们显示在 ListBox 中。

以下是一些相关代码:

     Private reader As New BinaryFormatter()
     Private input As FileStream
     input = New FileStream(fileName, FileMode.Open, FileAccess.Read)

     Dim record = CType(reader.Deserialize(input), TravelRecord)
     RequestLst.items.Add(record.toString())

这适用于返回第一条记录,但我希望它返回所有记录,以便我可以像下面这样遍历它们:

 For Each r As TravelRecord In records
            RequestLst.Items.Add(r.ToString())
        Next

我知道我可能遗漏了一些非常简单的东西,但我尝试的一切都会导致运行时错误。也可能有更好的方法来处理这个问题。

这是文件中序列化数据的样子。

  ÿÿÿÿ          DTravelRequest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null   TravelRequest.TravelRecord   ID FirstNameLastNamePurpose    StartDateEndDateAmount   System.Guid

   ýÿÿÿSystem.Guid   _a_b_c_d_e_f_g_h_i_j_k           “ŸPªO½cùømFÚw   Steve   Robinson   Semianr  U¾Ó €æ©PÓ     @o@ @_@    ÿÿÿÿ          DTravelRequest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null   TravelRequest.TravelRecord   ID    FirstNameLastNamePurpose    StartDateEndDateAmount   System.Guid

   ýÿÿÿSystem.Guid   _a_b_c_d_e_f_g_h_i_j_k           æ;o˜ùéAÎÜ^pñÌ   jake      Kirkbride   Stuff  l«™  Ó €CøX,Ô     À^@    ÿÿÿÿ          DTravelRequest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null   TravelRequest.TravelRecord   ID   FirstNameLastNamePurpose    StartDateEndDateAmount   System.Guid

   ýÿÿÿSystem.Guid   _a_b_c_d_e_f_g_h_i_j_k           FP“¼Î«Gž¥5tuUš   steve    stevenson   vacation @áw%Ó @ˆ!?(Ó     @_@    ÿÿÿÿ          DTravelRequest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null   TravelRequest.TravelRecord   ID  FirstNameLastNamePurpose    StartDateEndDateAmount   System.Guid

   ýÿÿÿSystem.Guid   _a_b_c_d_e_f_g_h_i_j_k           ‹MÆoh#D–âÑQþ…P   Steve    Stevenson   Program €œN4)Ô €CøX,Ô     @_@    ÿÿÿÿ          DTravelRequest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null   TravelRequest.TravelRecord   ID  FirstNameLastNamePurpose    StartDateEndDateAmount   System.Guid

   ýÿÿÿSystem.Guid   _a_b_c_d_e_f_g_h_i_j_k           k$ˆµ§FŠm§Íüâ   George    Govern   Stuff €CøX,Ô €ê¡/Ô      `@

看来我的问题是如何阅读所有这些并将它们变成一个集合,以便我可以使用它们。

这是 TravelRecord 类的代码:

    <Serializable()>
    Public Class TravelRecord

    'Class fields
    Public ID As Guid
    Public FirstName As String
    Public LastName As String
    Public Purpose As String
    Public StartDate As Date
    Public EndDate As Date
    Public Amount As Double

    Public Sub New()
        MyClass.New(Guid.Empty, String.Empty, String.Empty, String.Empty,
                    Nothing, Nothing, 0.0)
    End Sub

    Public Sub New(id As Guid, fName As String, lName As String,
                   purpose As String, startDate As Date, endDate As Date,
                   amount As Double)
        MyClass.ID = id
        MyClass.FirstName = fName
        MyClass.LastName = lName
        MyClass.Purpose = purpose
        MyClass.StartDate = startDate
        MyClass.EndDate = endDate
        MyClass.Amount = amount
    End Sub

    Public Overrides Function ToString() As String
        Return String.Format("0,-401,-102,-103,-154,12:d5,12:d6,12:C", _
            ID, FirstName, LastName, Purpose, StartDate, EndDate, Amount)
    End Function
End Class

来自 cmets:

序列化代码:

formatter.Serialize(output, travelRequest) 

其中 travelRequest 是 TravelRecord 的一个实例。

我可能需要更好地解释这一点。该系统供用户提交旅行记录。序列化设置为Append 一个新的 TravelRecord 到文件中,以充当数据库。 (这是我通常使用 SQL 的家庭作业)。反序列化是读取文件中的所有条目,并将它们显示在一个摘要列表框中。

反序列化只获取一个 TravelRecord 的原因是因为我不知道如何从文件中获取所有 TravelRecord。

有没有办法计算序列化文件中有多少项目,这样我就可以做一个有限的 For 循环之类的事情

【问题讨论】:

输出应该是一个集合吗?如果是这样,那么Dim records = CType(reader.Deserialize(input), List(Of TravelRecord)) 当我尝试收到以下未处理异常时:An unhandled exception of type 'System.InvalidCastException' occurred in TravelRequest.exe Additional information: Unable to cast object of type 'TravelRequest.TravelRecord' to type 'System.Collections.Generic.List1[TravelRequest.TravelRecord]'。 ` TravelRecord 是收藏吗?还是它包含一个集合?在第一个块中,您将其视为一个项目,在第二个块中,您将其视为列表或集合 您只是在该文件中写入和读取一项(来自此处的代码),所以我不知道文件中的其他内容是什么或它是如何到达那里的。当您确实将它设置为在集合上工作时,它可能是从早些时候开始的。我不确定 BF 是否为我们执行 File.Truncate 我不会考虑将 FileMode.Append 与序列化程序一起使用。它不会创建随机访问文件。您拥有的代码是不是来阅读它们,而是阅读一个。由于您一次写出一个,因此您必须以相同的方式读回它们,使用List(of TravelRecord) 更容易(您将如何删除记录 7 of 9?) 【参考方案1】:

你一次写一条记录:

formatter.Serialize(output, travelRequest)

因此您必须一次读回一条记录。 BinaryFomratter 将类型数据与数据 (TravelRecord) 一起存储,因此您不能将其作为集合(数组或 List(of TravelRecord))读回,因为它无法从一种类型转换为集合类型(没有一些gyrations 我确定你不想承担)。你可以在文件中看到 Type 数据:

TravelRequest、Version=1.0.0.0、Culture=neutral、PublicKeyToken...

该文件不会被随机访问,因此要获取记录 3 或找到“Foo”,您必须执行类似的操作(例如测试用户名 =“Bob”和Exit For)。代替TravelRecord 的是一个名为NVP 的类,我碰巧有它。

Function GetListofTravelRecords() As List(Of NVP)
    Dim tmpList As New List(Of NVP)
    Dim tmp As NVP

    Using fs As New FileStream("C:\Temp\nvplst.bin", FileMode.Open)
        Dim bf As New BinaryFormatter

        Do Until fs.Position >= fs.Length
            tmp = CType(bf.Deserialize(fs), NVP)
            tmpList.Add(tmp)
        Loop

    End Using
    Return tmpList

End Function

使用与测试:

Dim mylist = GetListofTravelRecords()

For Each item In mylist
    Console.WriteLine(item.ToString)
Next

输出:

齐格 (1) 扎基 (2) 佐伊 (3) 曲折 (4) 扎基 (5)

我在里面放了 11 件东西,它们都以相同的顺序安全返回。


提醒其他人,serialize an entire collection 并以 as 集合的形式读回它更容易。

【讨论】:

删除一条记录几乎是不可能的——您必须将它们全部读入一个集合或数组中,删除要删除的记录,然后将它们全部写回 感谢您为 Plutonix 付出的所有时间和努力。我知道这不是理想的情况,也不是 BF 的好用处。完成这周的作业后,我希望能够回到全栈 Web 开发,而不要管 BF 和序列化! BF 和序列化都很好......它一次一个 Append 是愚蠢的

以上是关于从要显示的文件中反序列化对象列表的主要内容,如果未能解决你的问题,请参考以下文章

在 symfony 中反序列化对象返回异常 [关闭]

我可以使用 protobuf-net 在 Mono 中序列化一个对象(包含成员:​​字典、列表...等)并在 MS.NET 中反序列化它,反之亦然?

在构造函数中反序列化 const 成员对象

在自定义JsonConverter中反序列化嵌套对象List

qt c ++中反序列化地图的大小增加

如何在 C# 中反序列化多个 JSON 对象?