VBfx / Common / Save and Load

Introduction

Saving and loading binary files is quite easy in VB. I'd say it's even easier than in text mode where you'd have to read a file line by line or split the data using tokens. And of course binary files are smaller because numbers are not converted to strings when saving. The only problem you get is when using open arrays, which also includes Strings - but that's not much, you just have to store the string length, too.

Opening files

Before you can access a file you need to open it, no matter if for reading or writing. The Open call needs a file number we can get from the FreeFile function. You can think of it being a slot number where the current file will be opened into.

When done accessing the file we have to close it again using the Close function. Here's the skeleton:

Dim FileNumber as Integer

'Get filenumber
FileNumber = FreeFile()

'Open file in binary mode
Open "C:\Test.dat" For Binary as FileNumber
    '
    'Write or Read data here
    '
Close FileNumber

There are some more access modes you can use instead of Binary, like Output, Input, Read, Write, Random, and so on. Search the web if you need to know more about those modes, I won't explain them here since we won't need them. Reading files in binary mode is always faster and better for our purposes.

Put and Get

When opened a file in binary mode you can either write or read data but you shouldn't mix it up in one function! The functions we need here are Put (write) and Get (read). Both accept 3 parameters:

As you can see the position is optional, in fact we won't ever use it so the code will always look like this:

Put FileNumber, , VarName

...and:

Get FileNumber, , VarName

(where VarName is the variable you're going to write or read into)

Strings

As mentioned before you can't directly Put or Get open arrays and Strings, this is because VB saves only the pure data and no descriptor. You can get around this by storing the data size manually. See the following example that writes a String to the file:

'Write string length
Put FileNumber, , Len( PlayerName )

'Write string
Put FileNumber, , PlayerName

Now to read it back from the file we have to tell VB what size the string is. This is done by reading the size first, then creating a (String) buffer of that size and finally read the data:

'Read string length
Get FileNumber, , Length

'Create string buffer
PlayerName = Space( Length )

'Read string
Get FileNumber, , PlayerName

Note that the Space() function creates a String of the specified length and fills it up with spaces. Get will then read as many characters as the passed variable (PlayerName) can hold. However to make life easier I made 2 functions that read and write a String variable just as Put and Get do, you can use them if you like:

Public Sub WriteString( iFileNumber as Integer, iString as String )
    'Write string data
    Put iFileNumber, , CLng( Len( iString ) )
    Put iFileNumber, , CStr( iString )
End Sub
Public Sub ReadString( iFileNumber as Integer, iString as String )
    Dim Temp as Long
    
    'Read string data
    Get iFileNumber, , Temp
    iString = Space( Temp )
    Get iFileNumber, , iString
End Sub

Note that the C... functions convert the data into the named type, eg. CLng() returns a Long value, CStr() returns a String, CInt() a Integer, CByte() a Byte value and so on.

Open arrays

As already mentioned we have to do the same for open arrays as we did for strings:

Dim PointList() as Long
Dim Ammunition() as Integer
Dim Directions() as Byte

First again we write the array size into the file. To get the size we can use the UBound() function that will return the 0-based size of the array (so 0 would still mean 1 item).

'Write array sizes
Put FileNumber, , UBound( PointList )
Put FileNumber, , UBound( Ammunition )
Put FileNumber, , UBound( Directions )

Now this is getting a little tricky and we can do this because the arrays are declared as a default data type (Long, Byte, Integer, Boolean and such). It wouldn't work if we used a UDT though.

'Write arrays
Put FileNumber, , PointList
Put FileNumber, , Ammunition
Put FileNumber, , Directions

Quite simple isn't it? You just have to pass the array and Put will write all of it's data into the file.

Reading arrays

Here again we have to read the size first, then create a buffer and finally read the data. Since the Space() function only works for Strings we have to use ReDim to set the size of the arrays:

'Read array sizes and create buffers
Get FileNumber, , Size
ReDim PointList( Size )

Get FileNumber, , Size
ReDim Ammunition( Size )

Get FileNumber, , Size
ReDim Directions( Size )

Finally reading the data is just the same as before, except that we have to use Get instead of Put:

'Write arrays
Get FileNumber, , PointList
Get FileNumber, , Ammunition
Get FileNumber, , Directions

UDT arrays

In fact you can just do the same as above for UDTs, but only as long as your UDT contains no arrays. However I don't recommend you to do this because in case you need to add or remove properties your files would screw up! Instead you should use loops to iterate through the array and Put each single property to the file manually.

Imagine the situation where you remove a property from the UDT. You could just use a temp variable when reading the file to skip the data no longer needed. Otherwise, if you added a new property you could just set the new property to a default value without reading anything from the file. Quite useful I tell you!

Conclusion

Binary files allow you to exactly control what data is written to the file. Also you can easily handle arrays of basic data types such as Long, Byte or Integer and when done correctly you can edit your UDTs later while keeping your files valid. Furthermore using a binary file will prevent most users to edit (or even view) the data, when opening a binary file in Notepad all you can see is the Strings stored there, no other data type will be readable for humen.

Navigation