![]() |
I have seen a lot of confusion and questions on the forums about writing and reading files, for level data, text files and suchlike, so I feel it would helpful for newbies/beginning programmers to have a tutorial about file access functions. Blitz really has an excellent set of file functions, and I will attempt to cover most of them.
First, a basic introduction to files in general. Information in a file on your computer is stored in Bytes. A byte is a value from 0 - 255, also represented by 8 Bits. A bit is either a 1 or a 0. Bytes are most easily represented in the Hexadecimal format, which uses base-16: the numbers 0 - 9, then the letters A - F. Each hex digit can be a value from 0 - 15, so 2 hex digits are a value from 0 - 255. For example, the value 255 is 'FF' in hex, or '11111111' in binary. You can pull up the Windows calculator and set it into 'Scientific Mode' to see this in action: Put in a decimal value, then select 'Hex', then select 'Binary' and you will see it convert. Text files vs. Binary: A text (.txt) file that can be read by Notepad or a similar program consists of the following: Text data, where each byte is the ASCII value corresponding to the text character, followed by carriage-return codes and linefeed codes ( chr$(13) and chr$(10), or Hex $0D and $0A). Many other file types are actually text files, including blitz basic program (.bb) files. Text files are good to use if:
A binary file can be almost anything, really, but the contents may or may not be readable in a text file viewer, you would need to use a hex editor to decipher the contents, or just read/write the data through blitz and not worry about what the contents look like. You can name the extension anything you like (i.e. .dat). Binary files are good to use if:
For this tutorial, we will create a simple, "Hello World" text file, then a simple map file.
Before you can start to read or write from a file, you need to open it, and sometimes create it. There are three main commands for this, each for a different purpose.
Handles and Return values It is important to understand how to use a Handle to use this command properly. A handle is a variable that will be used to reference the file without having to use the filename. The syntax for using the above commands is as follows:
So, to make our "Hello World" file, we would begin with:
This will create a new, blank file in the current directory, with the handle 'myfile'. Now, anytime we reference the file we can just say 'myfile' instead of "Hello.txt". All three of these commands will return a zero if it was unable to complete the command. For example, if you had used ReadFile() and the file did not exist, the handle will have a value of zero. This is handy to test for incorrect or missing files. After the command, you can include the following code:
This will cause the program to bail out if there was a problem. You do not have to do this, but it is follows good programming practices. O.k., now we have a file open and ready for the next step…
There are quite a few commands for reading and writing to a file, and it helps to use the right one for the job. Here is a chart:
*A note on syntax: all of the READ commands require the parentheses. The WRITE commands do not, although you can use them if you want. 'WriteByte myfile,10' is acceptable, and so is 'WriteByte(myfile,10)'. There is also ReadBytes and WriteBytes for passing data from files to banks, but that is out of the scope of this tutorial. Remember that you can use any combination of the above commands, so long as you read them back in the same order that you wrote them. File Position and EOF Files in blitz are read sequentially, from beginning to end. Blitz automatically keeps track of where you are in the file, so if you read data out in the same order you put it in, you don't need to do anything to track the file position. However, if you need to, the file position is there for you handily named FilePos(). You can use the SeekFile() command to move that position around if you need to. If the file position is at the end of the file, the EOF() (end-of-file) function will return True. So, when you first open/create the file, the filepos() will be automatically at '0'. If you do a 'writebyte' function, the position will move one byte, 'writeint' it will move 4 bytes, etc. Example:
Back to our tutorial example: So far we have this:
So now we can write to the file. We'll start with WriteLine()
Voila! That was easy, huh? Now let's do it one character at a time:
O.k., now let's read the file:
That's all there is to it. Now, a simple mapfile save/load routine: (See Krylar's tutorial for more on map files. This is just to see an example of writing/reading different variable types to file.) We have a 30x30 grid of tiles, in an array that simply keeps track of the Frame number for the given tile. We will store the map name, description, width and height and then the array into a file. Assuming you have an array map(x,y):
Hex editing If you find yourself doing a lot of file operations, it is a good idea to get a Hex Editor program - a program that lets you look 'under the hood' of your files, to see what the file looks like to the computer. I use XVI32, found here: http://www.chmaas.handshake.de/delphi/freeware/xvi32/xvi32.htm. It's free, and full featured.
Here's what our "Hello.txt" file looks like in the hex editor:
Note the first byte, '48' in hex, which is '72' in decimal, is the ASCII code for an upper-case H. Also note the space is hex '20' which is '32' in decimal. At the end is '0D' and '0A', which is 13 and 10, carriage return and line feed codes. That shows that this is readable as a text file. Byte order (significance) If we enter the following code:
And then look at the file in the hex editor we see:
You might not understand how the above is equal to '2000'. This is because the integer data stored on disk is stored Least Significant Byte first. If you use the windows calculator and convert '2000' to hex, you see it is $7D0. But, on a PC it is stored backwards, byte-by-byte, so you have $D0 (dec 208) + (7 * 256) which is 2000. The remaining 2 bytes are not needed for this value, but WriteInt will use 4 bytes regardless. In this case we could have used WriteShort to write the value with 2 bytes.
Now we should know:
Any questions (or if you spot any mistakes!), feel free to email me at timsanford@pacificadhesives.com. Thanks to Krylar for posting this tutorial, and for providing an excellent web resource for the excellent Blitz Basic/Blitz3D programs.
For a printable copy of this article, please click HERE.
This site is Copyright© 2000-2004, BlitzCoder. All rights reserved.
|