Post

Tip: Read/Write Structures using FileStream

Although VB.NET includes support for the VB6 style file FreeFile, Open, Get, Put, Close, etc. functions; they are ridiculously slower than using FileStream (or even their VB6 counterparts - which is really strange) for large (1 mb+) files. The other, more serious, issue with these functions is that with Option Strict On, you are unable to read/write structures?!?! Here is a suggested solution to this problem. I’m hoping by writing this that others may be able to offer additional options for accomplishing the same task.

First things first, let’s add out Imports statement so we can save ourselves some typing.

1
Imports System.Runtime.InteropServices

Then create a demo structure to work with. I want to point out the fact that there are String values present in the structure.

1
2
3
4
5
6
7
8
<StructLayout(LayoutKind.Sequential)> _
Public Structure Person
  Public Age As Int32
  <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=5)> _
  Public FirstName As String
  <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=5)> _
  Public LastName As String
End Structure

Now for the code to read and write this structure as a binary representation of the data only. When reading / writing, not wanting the extra data the helps to define the structure, just the data itself.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
' Writing to file.
Dim person As New Person
person.FirstName = "John"
person.LastName = "Doe"
person.Age = 21

Dim data(Marshal.SizeOf(person)) As Byte
Dim handle As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned)
Dim ptr As IntPtr = handle.AddrOfPinnedObject()
Marshal.StructureToPtr(person, ptr, False)
handle.Free()
Debug.WriteLine(BitConverter.ToString(data))

With New IO.FileStream("person.bin", _
                       IO.FileMode.OpenOrCreate, _
                       IO.FileAccess.ReadWrite, _
                       IO.FileShare.None)
  .Write(data, 0, data.Length)
  .Close()
End With

' Reading from file.
With New IO.FileStream("person.bin", _
                       IO.FileMode.OpenOrCreate, _
                       IO.FileAccess.ReadWrite, _
                       IO.FileShare.None)
  .Read(data, 0, data.Length)
  .Close()
End With
handle = GCHandle.Alloc(data, GCHandleType.Pinned)
ptr = handle.AddrOfPinnedObject()
Dim newPerson As Person = DirectCast(Marshal.PtrToStructure(ptr, GetType(Person)), Person)
handle.Free()
Debug.WriteLine(String.Format("{0}, {1}", newPerson.FirstName, newPerson.Age))
Debug.WriteLine(BitConverter.ToString(data))

Using this method, you can switch to using the FileStream and have Option Strict On enabled. Hopefully, someone will chime in with additional options to solve this issue.

This post is licensed under CC BY 4.0 by the author.