1

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.

Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
ChemTchr
  • 13
  • 3
  • 1
    Did I give you the proper credit (votes?) for a great answer? I adopted all your suggestions, changed my approach and all worked out as you said. Many Thanks – ChemTchr Jun 24 '17 at 21:44
  • yes. Accepting answers (the checkmark) is all you can do until you get a little more rep. Then you can upvote any post you find helpful. – Ňɏssa Pøngjǣrdenlarp Jul 01 '17 at 19:56

1 Answers1

2

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...

Use a Class not a Structure

MSDN has a good article one when and why to use a Class rather than a Structure. See Choosing Between Class and Struct

Use a List instead of an array

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.

Do not use GetBuffer

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...

Use a FileStream

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/2005

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

See also: Beginner's Guide to Classes and Lists

Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178