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.
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.
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
Get FileNumber, , VarName
(where VarName is the variable you're going to write or read into)
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.
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.
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
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!
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.