如何将 MemoryStream 反序列化为 Structs 数组

How can I deserialize a MemoryStream to an array of Structs

我有一个 Structure (Person) 数组,我将其序列化并格式化如下

  <Serializable()> Structure Person
        Public strID As String
        Public strName As String
        Public strReport As String
        Public strAttend As String

    Public Shared Widening Operator CType(v As Person) As IO.MemoryStream
        Try
            Throw New NotImplementedException()
        Catch ex As Exception
            MsgBox("Failed to deserialise." + Chr(13) + "Reason: " & ex.Message)
        End Try
    End Operator
End Structure

Public Student(35) As Person
Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
Dim ms as New System.IO.MemorySteam()

bf.Serialize(ms,Student(count))
My.Computer.FileSystem.WriteAllBytes(strFile1,ms.GetBuffer(),True)

文件已根据需要创建和填充。当我用写字板检查时,所有记录都存在。 当我反序列化它时,如下所示,我只看到重复的第一条记录。我在想要么指针没有移动,要么我要在每次迭代时返回记录 1。我错过了什么?

Public Student(35) As Person
Dim bf As New    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
Dim ms as New System.IO.MemorySteam()
Dim bytes As Byte() = My.Computer.FileSystem.ReadAllBytes(strFile1)
My.Computer.FileSystem.ReadAllBytes(strFile1)
Student(35) = DirectCast(bf.Deserialize(New MemoryStream(bytes)),Person)
ms.Seek(0,SeekOrigin.Begin)

For i = 0 to 19
    Student(i) = DirectCast(bf.Deserialize(New MemoryStream(bytes)),Person)
Next

提前感谢您提供的任何帮助或建议。

您的处理方式有很多错误。从根本上说,您可以而且应该立即序列化和反序列化整个集合。您不能逐项遍历内存流,因为您不知道(不能)知道每条记录的序列化大小。但还有更多...

使用 Class 而不是结构

MSDN 上有一篇很好的文章,介绍何时以及为何使用 Class 而不是 Structure。参见 Choosing Between Class and Struct

使用列表而不是数组

数组很难处理,因为您现在需要达到所需的大小。特别是对于硬编码的幻数,如果学生人数减少(或增加),您将不希望必须重写应用程序以更改 35 所有地方。

A List(Of T) 根据需要增长。

不要使用 GetBuffer

MemoryStream 使用的内部缓冲区会根据需要自行增长。但它通过每次 双倍 缓冲区大小来实现。这意味着几乎一半的缓冲区可能未被使用 space。使用 .ToArray() 获取使用的部分。请参阅 MemoryStream.GetBuffer Method - 阅读备注部分。

但你甚至不需要 MemoryStream...

使用文件流

与其写入 memstream 只是为了将其写入文件,您可以打开文件流并直接写入(或读取)它:

我的Class:

<Serializable()>
Public Class Student
    Public Property Name As String
    Public Property Gender As String

    Public Property EnrollDate As Date
    Public Property FavoriteColor As String

    Public Sub New()

    End Sub
    Public Sub New(n As String)
        Name = n
    End Sub

    Public Overrides Function ToString() As String
        Return Name & "     " & EnrollDate
    End Function
End Class

ToString() 覆盖是为了方便 debugging/demo。在 List(Of T):

中创建 Student 对象的集合
Dim Students As New List(Of Student)()
Dim s As Student

s = New Student("Ziggy F")
s.EnrollDate = #5/17/2007#
s.Gender = "M"
s.FavoriteColor = "Orange"
Students.Add(s)
... etc

Console.WriteLine("BEFORE")
For Each s In Students
    Console.WriteLine(s)
Next

序列化:

Dim filename As String = "C:\Temp\myStudents.dat"

Using fs As New FileStream(filename, FileMode.Create)
    Dim bf As New BinaryFormatter
    bf.Serialize(fs, Students)
End Using

反序列化和测试:

Dim newStudents As List(Of Student)
' to do check if exists
Using fs As New FileStream(filename, FileMode.Open)
    Dim bf As New BinaryFormatter
    newStudents = DirectCast(bf.Deserialize(fs), List(Of Student))
End Using

Console.WriteLine("AFTER")
For Each s In newStudents
    Console.WriteLine(s)
Next

我所有的学生都完成了往返:

BEFORE
Ziggy F 5/17/2007
Zoey P 8/1/2007
Hoover M 7/21/2005

AFTER
Ziggy F 5/17/2007
Zoey P 8/1/2007
Hoover M 7/21/2005

另请参阅: