I have an array of Structure (Person) which I serialized and formatted as follows
<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)
The file is created and populated as desired. When I check it with WordPad all records are present. When I deserialize it, as below, I am only seeing the first record repeated. I am thinking either the pointer is not moving or I am going back to record 1 on each iteration. What am I missing?
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
Thank you, in advance, for any help or suggestions you may offer.
There is a fair amount wrong with the way are you going about it. Fundamentally, you can and should serialize and deserialize the entire collection at once. You cant step thru the memorystream item by item because you dont (cant) know the serialized size of each record. But there is more...
MSDN has a good article one when and why to use a Class
rather than a Structure
. See Choosing Between Class and Struct
Arrays are grody and hard to work with because you need to now the size needed. Especially with hard coded magic numbers, if the number of students shrinks (or grows), you would not want to have to rewrite the app to change 35
everywhere.
A List(Of T)
grows as needed.
The internal buffer used by a MemoryStream
grows by itself as needed. But it does so by doubling the buffer size each time. Which means almost half the buffer could be unused space. Use .ToArray()
to get the used portion. See MemoryStream.GetBuffer Method - read the Remarks section.
But you do not even need a MemoryStream
...
Rather than write to a memstream only to write it a file, you can open a filestream and write (or read) directly to that:
My 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
The ToString()
override is to facilitate debugging/demo. Create a collection of Student
object in a List(Of T)
:
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
Serialize:
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
Deserialize and test:
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
All my students made the round trip:
BEFORE
Ziggy F 5/17/2007
Zoey P 8/1/2007
Hoover M 7/21/2005AFTER
Ziggy F 5/17/2007
Zoey P 8/1/2007
Hoover M 7/21/2005
See also: Beginner's Guide to Classes and Lists