So, you have an .ini or .txt file that contains some user modifiable values and you want your program to have the ability to load these values and use them and/or write these values back to the file?
There are many ways that you could implement reading or writing to the file. This tutorial will discuss only a few of the methods that you could use.
Let's say you have some variables in your program that need to be initialized with some values from a user editable file called gamefile.txt.
Let's also say that our test file (gamefile.txt) contains these 7 lines:
[graphics]
width=1024
height=768
colordepth=16
[sound]
sounds=on
volume=50
You could use one of the following methods to read in the file:
********Method 1:
Parse through each line looking for keywords.
First we look for bracketed sections and then load individual parameters within those sections into our program variables. The code uses the Lower$ function to eliminate the dozens of variations a parameter could be written using upper and lowercase characters. If the code finds a line that begins with another opening brace, then it assumes there are no more parameters in that section. After parsing through the graphics section of gamefile.txt it uses a SeekFile(filein, 0) to start once again at the beginning of the file searching for the sound section. Notice also in the sound section that the sounds=on line doesn't have a numerical value but it is still taken care of by the code.
A downfall of this specific code is that it is checking for keywords on each line with the equal sign immediately following the keyword (i.e. volume=). If the file was modified and the line read "volume =" (notice the space between volume and =) then this code would fail to load the value. This code could be modified to search for only the keyword and then parse furthur through the line to remove any extra characters before the data.
Another downfall of this code is that it's hardcoded. It's not very flexible. To load a different parameter, you have to add more code to it to handle that. Another way is to change this code into the form of a function that can write/read whatever values you pass to it.
Rob Farley has written a function that uses a similar method to both read and write data from/to the file. You can find it in the code archives here:
www.blitzbasic.com/codearcs/codearcs.php?code=776
********Method 2:
Read from a structured file.
This method allows you to load values from the file without needing to parse through the file (providing that you know the order of the parameters in the file). The file can be structured in such a way that every line is the same length. This way you can easily load any line simply by using SeekFile() to point to the desired line and read in a certain amount of characters.
You could have a structure something like this:
variablename = floatingpointvalue
SeekFile'ing to (3 - 1) times 27(the linelength) plus 13(offset to value part of the line)
and ReadByte'ing in the next 14 characters (the length of the value portion)
The downfall to this method is that if a user were to modify the file and change the structure in any way, it would become corrupted.
Let's say you have some variables in your program that need to be saved to a file called gamefile.txt.
For starters, let's say that gamefile.txt already contains these 5 lines:
difficulty=3
gamma=0.5
volume=75
zoffsetvalue=45903.239594
xoffsetvalue=1003478.002
Let's also say that you want to change the gamma value in the file from 0.5 to 0.8. How would you do it? It's not as simple as it sounds.
Basically there are two ways:
1. Modify specific bytes within the file
2. Overwrite the entire file.
First of all, a note about trying to modify specific bytes within the file:
Writing on a specific line is complicated because all data in the file is actually sequential. This means that the volume=75 line immediately follows the gamma=0.5 line (and the line feed character(s)). If you tried to edit the file by using OpenFile and then SeekFile'ing to the desired byte, WriteByte'ing the desired byte(s), and then Closefile the results may not be what you expect. If the number of bytes you write are shorter or longer than the number of bytes already there, you will mess up the file.
What I am getting at is that if you were to replace 0.5 with 0.8 for example, then there would be no problem. BUT, if you were to replace 0.5 with .5 or 0.83 then funny things would happen. .5 would actually become .55 and 0.83 would become 0.83 but the three would write over the first character of the next line which would make your gamma= statement equal everything on the following line as well.
That being said, I will show you three ways you could modify the file:
********Method 1:
Write to a structured file.
One method you could implement would be to structure your file in such a way that you don't use variable length lines. Every line in your file is exactly the same length so you can easily change any line and know that you won't overwrite anything else. You could have a structure something like this:
variablename = floatingpointvalue
This way if you wanted to change any given value (say the volume percent to 80), you could just skip to the third 'line' by
SeekFile'ing to (3 - 1) times 27(the linelength) plus 13(offset to value part of the line)
and WriteByte'ing the characters
The downfall to this method is that if a user were to modify the file and change the structure in any way, it would become corrupted.
The advantage to this type of file is that you can open the file once and continually write to any given parameter within the file without writing over any other data and without having to rewrite the entire file. In other words, random access.
********Method 2:
Read the file in to an array.
Read each line of the file in to an array, modify the line you wish and then write back the entire file one line at a time.
********Method 3:
Read the entire file in to two strings. Write back the entire file as first string + your change + last string.
Using the SeekFile and FilePos commands:
-find the spot that requires changing by parsing through the file until you find the phrase your are looking for (such as "gamma")
-note the FilePos where you found the phrase
-store everything before that spot (FilePos) in a string variable (say Beginning$)
-store everything after that spot in another string variable (say Remainder$)
-overwrite the entire file with: Beginning$ + "0.8" + Remainder$
**************************************
This tutorial should be enough to get you started. Please let me know (check for my email address under WolRon) if there is any way you think this tutorial could be improved.
Ignore the signature :)
There are many ways that you could implement reading or writing to the file. This tutorial will discuss only a few of the methods that you could use.
***************Reading in the file***************
Let's say you have some variables in your program that need to be initialized with some values from a user editable file called gamefile.txt.
Let's also say that our test file (gamefile.txt) contains these 7 lines:
[graphics]
width=1024
height=768
colordepth=16
[sound]
sounds=on
volume=50
You could use one of the following methods to read in the file:
********Method 1:
Parse through each line looking for keywords.
First we look for bracketed sections and then load individual parameters within those sections into our program variables. The code uses the Lower$ function to eliminate the dozens of variations a parameter could be written using upper and lowercase characters. If the code finds a line that begins with another opening brace, then it assumes there are no more parameters in that section. After parsing through the graphics section of gamefile.txt it uses a SeekFile(filein, 0) to start once again at the beginning of the file searching for the sound section. Notice also in the sound section that the sounds=on line doesn't have a numerical value but it is still taken care of by the code.
Global GfxWidth=640 Global GfxHeight=480 Global GfxDepth=16 Global Snd=True Global SndVol=50 filein = OpenFile("Gamefile.txt") If filein <> 0 ;load graphics mode foundit = 0 Repeat If Lower(ReadLine$(filein))="[graphics]" Then foundit = 1 Until Eof(filein) Or foundit = 1 If foundit done = False Repeat param$ = Lower(ReadLine$(filein)) If Left$(param$, 6) = "width=" val = Right$(param$, Len(param$) - 6) If val = 1024 or val = 800 Then GfxWidth = val EndIf If Left$(param$, 7) = "height=" val = Right$(param$, Len(param$) - 7) If val = 768 or val = 600 Then GfxHeight = val EndIf If Left$(param$, 11) = "colordepth=" val = Right$(param$, Len(param$) - 11) If val = 16 Or val = 24 Or val = 32 Then GfxDepth = val EndIf If Left$(param$, 1) = "[" Or Eof(filein) Then done = True Until done = True EndIf ;load sound parameters SeekFile(filein, 0) foundit = 0 Repeat If Lower(ReadLine$(filein))="[sound]" Then foundit = 1 Until Eof(filein) Or foundit = 1 If foundit done = False Repeat param$ = Lower(ReadLine$(filein)) If Left$(param$, 7) = "sounds=" word$ = Right$(param$, Len(param$) - 7) If word$ = "on" Snd = True Else Snd = False EndIf EndIf If Left$(param$, 7) = "volume=" val = Right$(param$, Len(param$) - 7) If val > -1 And val < 101 Then SndVol = val EndIf If Left$(param$, 1) = "[" Or Eof(filein) Then done = True Until done = True EndIf ;close file CloseFile filein filein = 0 Else DebugLog "File Not Found" EndIf ;filein <> 0
A downfall of this specific code is that it is checking for keywords on each line with the equal sign immediately following the keyword (i.e. volume=). If the file was modified and the line read "volume =" (notice the space between volume and =) then this code would fail to load the value. This code could be modified to search for only the keyword and then parse furthur through the line to remove any extra characters before the data.
Another downfall of this code is that it's hardcoded. It's not very flexible. To load a different parameter, you have to add more code to it to handle that. Another way is to change this code into the form of a function that can write/read whatever values you pass to it.
Rob Farley has written a function that uses a similar method to both read and write data from/to the file. You can find it in the code archives here:
www.blitzbasic.com/codearcs/codearcs.php?code=776
********Method 2:
Read from a structured file.
This method allows you to load values from the file without needing to parse through the file (providing that you know the order of the parameters in the file). The file can be structured in such a way that every line is the same length. This way you can easily load any line simply by using SeekFile() to point to the desired line and read in a certain amount of characters.
You could have a structure something like this:
variablename = floatingpointvalue
AAAAAAAAAAAA=XXXXXXX.XXXXXX width = 1024 height = 768 colordepth = 16 sounds =on volume = 50This way if you wanted to load any given value (say the colordepth), you could just skip to the third 'line' by
SeekFile'ing to (3 - 1) times 27(the linelength) plus 13(offset to value part of the line)
and ReadByte'ing in the next 14 characters (the length of the value portion)
The downfall to this method is that if a user were to modify the file and change the structure in any way, it would become corrupted.
****************Modifying the file***************
Let's say you have some variables in your program that need to be saved to a file called gamefile.txt.
For starters, let's say that gamefile.txt already contains these 5 lines:
difficulty=3
gamma=0.5
volume=75
zoffsetvalue=45903.239594
xoffsetvalue=1003478.002
Let's also say that you want to change the gamma value in the file from 0.5 to 0.8. How would you do it? It's not as simple as it sounds.
Basically there are two ways:
1. Modify specific bytes within the file
2. Overwrite the entire file.
First of all, a note about trying to modify specific bytes within the file:
Writing on a specific line is complicated because all data in the file is actually sequential. This means that the volume=75 line immediately follows the gamma=0.5 line (and the line feed character(s)). If you tried to edit the file by using OpenFile and then SeekFile'ing to the desired byte, WriteByte'ing the desired byte(s), and then Closefile the results may not be what you expect. If the number of bytes you write are shorter or longer than the number of bytes already there, you will mess up the file.
What I am getting at is that if you were to replace 0.5 with 0.8 for example, then there would be no problem. BUT, if you were to replace 0.5 with .5 or 0.83 then funny things would happen. .5 would actually become .55 and 0.83 would become 0.83 but the three would write over the first character of the next line which would make your gamma= statement equal everything on the following line as well.
In this example < will represent line feed character. Only the first three lines of our test file are shown in this example. difficulty=3<gamma=0.5<volume=75 ;changed to 0.8 would be difficulty=3<gamma=0.8<volume=75 ;just what you want difficulty=3<gamma=0.5<volume=75 ;changed to .5 would be difficulty=3<gamma=.55<volume=75 ;extra 5 wasn't erased difficulty=3<gamma=0.5<volume=75 ;changed to 0.83 would be difficulty=3<gamma=0.83volume=75 ;line feed character erased so now gamma = 0.83volume=75
That being said, I will show you three ways you could modify the file:
********Method 1:
Write to a structured file.
One method you could implement would be to structure your file in such a way that you don't use variable length lines. Every line in your file is exactly the same length so you can easily change any line and know that you won't overwrite anything else. You could have a structure something like this:
variablename = floatingpointvalue
AAAAAAAAAAAA=XXXXXXX.XXXXXX difficulty = 3 gamma = 0.5 volume = 75 zoffsetvalue= 45903.239594 xoffsetvalue=1003478.002
This way if you wanted to change any given value (say the volume percent to 80), you could just skip to the third 'line' by
SeekFile'ing to (3 - 1) times 27(the linelength) plus 13(offset to value part of the line)
and WriteByte'ing the characters
" 80 "(exactly 14 characters long) (NOTE that you wouldn't actually write the quotes, they are just there for clarity) The downfall to this method is that if a user were to modify the file and change the structure in any way, it would become corrupted.
The advantage to this type of file is that you can open the file once and continually write to any given parameter within the file without writing over any other data and without having to rewrite the entire file. In other words, random access.
********Method 2:
Read the file in to an array.
Read each line of the file in to an array, modify the line you wish and then write back the entire file one line at a time.
Const MAXLINES 200 Dim dat$(MAXLINES) ; read file filein=ReadFile("gamefile.txt") linecount=0 While Not Eof(filein) linecount=linecount+1 dat$(linecount)=ReadLine(filein) If linecount=MAXLINES Exit Wend CloseFile filein ;modify file dat$(2)="gamma=0.8" ; write file fileout=WriteFile("gamefile.txt") For i=1 To linecount WriteLine fileout,dat$(i) Next CloseFile fileout
********Method 3:
Read the entire file in to two strings. Write back the entire file as first string + your change + last string.
Using the SeekFile and FilePos commands:
-find the spot that requires changing by parsing through the file until you find the phrase your are looking for (such as "gamma")
-note the FilePos where you found the phrase
-store everything before that spot (FilePos) in a string variable (say Beginning$)
-store everything after that spot in another string variable (say Remainder$)
-overwrite the entire file with: Beginning$ + "0.8" + Remainder$
**************************************
This tutorial should be enough to get you started. Please let me know (check for my email address under WolRon) if there is any way you think this tutorial could be improved.
Ignore the signature :)