Search code examples
vb.netread-write

How would I write formatted data to a file and then read it? VB.NET (2012 edition)


I'm practicing VB.NET and I've got a problem with Reading and writing to a .dat file. I have made a structure to store data temporarily (below).

Structure CustomerType
    Dim AccountNum As String
    Dim Surname As String
    Dim Forename As String
    Dim Balance As Decimal
End Structure

I then Dim everything.

Dim Customers(9) As CustomerType
Dim Filename As String = "Accounts.dat"
Dim NumberOfRecords As Short = 0
Dim myFormat As String = "{0,-15}|{1,-15}|{2,-10}|{3,-10}"

I have a button that creates a new account and this is where I get the problem.

    FileOpen(1, Filename, OpenMode.Random, , , )
    For i = 1 To Customers.Length() - 1
        With Customers(i)
            .Forename = InputBox("First name", "Forename")
            Do Until .Forename <> "" And TypeOf .Forename Is String
                .Forename = InputBox("First name", "Forename")
            Loop
            .Surname = InputBox("Surname", "Surname")
            Do Until .Surname <> "" And TypeOf .Surname Is String
                .Surname = InputBox("Surname", "Surname")
            Loop
            .AccountNum = InputBox("Account Number of " & Customers(i).Forename & " " & Customers(i).Surname & ".", "Account Number")
            Do Until .AccountNum.Length = 8 And TypeOf .AccountNum Is String
                .AccountNum = InputBox("Account Number of " & Customers(i).Forename & " " & Customers(i).Surname & ".", "Account Number")
            Loop
            .Balance = InputBox("Balance of " & Customers(i).Forename & " " & Customers(i).Surname & ".", "Balance")
            Do Until .Balance > -1
                .Balance = InputBox("Balance of " & Customers(i).Forename & " " & Customers(i).Surname & ".", "Balance")
            Loop
            FilePut(1, Customers, NumberOfRecords + 1)
            NumberOfRecords += 1
            lblNumberOfRecords.Text = NumberOfRecords
        End With
    Next
    FileClose(1)

I have another button that displays the data in a listbox. I can only get one item to display before I get a bad length error.

    Dim Index As Integer
    ListBox1.Items.Clear()
    ListBox1.Items.Add(String.Format(myFormat, "Forename", "Surname", "Acc. Num.", "Balance"))
    ListBox1.Items.Add("_____________________________________________________")
    FileOpen(1, Filename, OpenMode.Random, , , )
    For Index = 1 To NumberOfRecords
        FileGet(1, Customers)
        ListBox1.Items.Add(String.Format(myFormat, Customers(Index).Forename, Customers(Index).Surname, Customers(Index).AccountNum, Format(Customers(Index).Balance, "currency")))
    Next Index
    FileClose(1)

The main question that I have is What am I doing wrong, and how can I fix it?

Many Thanks in advance, Jordan


Solution

  • First you'll need to import these namespaces:

    Imports System.Runtime.Serialization
    Imports System.Runtime.Serialization.Formatters.Binary
    Imports System.IO
    

    Model

    Change your customertype model to this:

    <Serializable()> _
    Public Class CustomerType
        Implements ISerializable
    
        Public Sub New()
        End Sub
    
        Protected Sub New(info As SerializationInfo, context As StreamingContext)
            Me.AccountNum = info.GetString("AccountNum")
            Me.Surname = info.GetString("Surname")
            Me.Forename = info.GetString("Forename")
            Me.Balance = info.GetDecimal("Balance")
        End Sub
    
        Public AccountNum As String
        Public Surname As String
        Public Forename As String
        Public Balance As Decimal
    
        Public Sub GetObjectData(info As System.Runtime.Serialization.SerializationInfo, context As System.Runtime.Serialization.StreamingContext) Implements System.Runtime.Serialization.ISerializable.GetObjectData
            info.AddValue("AccountNum", Me.AccountNum)
            info.AddValue("Surname", Me.Surname)
            info.AddValue("Forename", Me.Forename)
            info.AddValue("Balance", Me.Balance)
        End Sub
    
    End Class
    

    Your model do now support serialization. Next step is to create functions to read/write a model collection to/from a file.

    Write

    Friend Shared Sub Write(filePathAndName As String, list As List(Of CustomerType))
        Dim formatter As IFormatter = New BinaryFormatter()
        Using stream As New FileStream(filePathAndName, FileMode.Create, FileAccess.Write, FileShare.None)
            formatter.Serialize(stream, list)
        End Using
    End Sub
    

    Read

    Friend Shared Function Read(filePathAndName As String) As List(Of CustomerType)
        Dim formatter As IFormatter = New BinaryFormatter()
        Dim list As List(Of CustomerType) = Nothing
        Using stream As New FileStream(filePathAndName, FileMode.Open, FileAccess.Read, FileShare.None)
            list = DirectCast(formatter.Deserialize(stream), List(Of CustomerType))
        End Using
        Return list
    End Function
    

    Usage

    Drop a button named Button1 onto a form named Form1 and add this code:

    Public Class Form1
    
        Public Sub New()
            Me.InitializeComponent()
        End Sub
    
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    
            Dim path As String = "C:\test.dat" '<- Change to desired path
            Dim list As New List(Of CustomerType)
    
            'Create test item1 and add to list.
            Dim item1 As New CustomerType()
            With item1
                .AccountNum = "1"
                .Balance = 1000D
                .Forename = "Forename 1"
                .Surname = "Surname 1"
            End With
            list.Add(item1)
    
            'Create test item2 and add to list.
            Dim item2 As New CustomerType()
            With item2
                .AccountNum = "2"
                .Balance = 2000D
                .Forename = "Forename 2"
                .Surname = "Surname 2"
            End With
            list.Add(item2)
    
            'Write to file:
            Write(path, list)
    
            'Read from file into new list:
            Dim list2 As List(Of CustomerType) = Read(path)
    
            MsgBox(String.Format("Count={0}", list2.Count))
    
        End Sub
    
        Friend Shared Sub Write(filePathAndName As String, list As List(Of CustomerType))
            Dim formatter As IFormatter = New BinaryFormatter()
            Using stream As New FileStream(filePathAndName, FileMode.Create, FileAccess.Write, FileShare.None)
                formatter.Serialize(stream, list)
            End Using
        End Sub
    
        Friend Shared Function Read(filePathAndName As String) As List(Of CustomerType)
            Dim formatter As IFormatter = New BinaryFormatter()
            Dim list As List(Of CustomerType) = Nothing
            Using stream As New FileStream(filePathAndName, FileMode.Open, FileAccess.Read, FileShare.None)
                list = DirectCast(formatter.Deserialize(stream), List(Of CustomerType))
            End Using
            Return list
        End Function
    
    End Class