Lesson Three - Reading and Writing Sequential Files
Copyright 2007 Shoptalk Systems
All Rights Reserved
Reading and Writing Sequential Files
Now we will learn about how to work with disk files. With few exceptions, all
personal computers have at least one floppy disk drive and one hard disk drive.
Run BASIC provides ways to write information to disk files on these devices, and
we can take advantage of this when we write our programs.
There are two ways to read and write files in Run BASIC. One is called
sequential and the other is called random access. We will use the sequential
method for our examples here. The reason it is called sequential is that
when reading or writing we start at the beginning of the file and work one item
at a time to the end. An item can be words or characters separated by commas, or
an item can be a complete line of data.
Let's familiarize ourselves with a few Run BASIC statements that help us work
with files.
OPEN
The OPEN statement causes Run BASIC to open a file. A file must be opened if we
want to write into it or read from it. There are several ways to open any file
for sequential access. These 'ways' are called modes.
The OUTPUT mode: The OUTPUT mode is for writing to a file. This is what an OPEN
statement for OUTPUT looks like:
open "myfile.txt" for output as
#myHandle
You can see the OUTPUT mode is specified. The last item on the line is
#myHandle. It is a name (called a file handle) given to Run BASIC to use for the
open file. Any code that writes to this file must include a reference to
#myHandle. This is so that Run BASIC knows which file to write to.
A file handle starts with a # character followed by any word or sequence of
characters (using letters and digits). It is best to choose handles that make it
easy for you to remember which file you are working with while writing your
program. Some examples of valid file handles are:
#1
#abc
#dataFile
#customers
You cannot have more than one file open at a time that uses the same file handle
or your program will terminate with an error.
The INPUT mode: There is also a mode for reading sequentially from a file. This
mode is called INPUT. Here is an example of an OPEN statement for INPUT:
open "myfile.txt" for input as
#myHandle
CLOSE
The CLOSE statement is used for closing open files when we are done reading or
writing them. This is a required operation when working with files and it is a
very important thing to remember when writing programs.
Here is how OPEN and CLOSE work together:
open "myfile.txt" for output as
#myHandle
'put some code in here that writes to #myHandle
close #myHandle
Another thing to remember is that a file opened for one mode must first be
closed before it can be opened for a different mode. If you are going to read
from a file you've just written to, you must close the file and reopen it, like
so:
open "myfile.txt" for output as
#myHandle
'put some code in here that writes to #myHandle
close #myHandle
open "myfile.txt" for input as #myHandle
'put some code in here that reads from #myHandle
close #myHandle
PRINT
We've already seen how the PRINT statement can display text into a window on the
screen. PRINT can also be used to write into a file opened for sequential
OUTPUT. Here is an example:
open "myfile.txt" for output as
#myHandle
print #myHandle, "Hello"
print #myHandle, "World!"
close #myHandle
This little program produces a file containing two lines of text (each could be
considered an item, see above). Type the code in and run it. When the program
finishes executing, open Windows Notepad on MYFILE.TXT to see the
result!
Let's Take It For A Spin
Now we'll modify the AGES.BAS program from out WK2SOL.TXT file so that it saves
the names and ages that we enter into a file. Take a look at this modified
program:
'AGES.BAS
'Accept some names and ages from the user, then total and average them
dim numbers(20)
dim names$(20)
print "AGES.BAS"
print
'loop up to 20 times, getting numbers
print "Enter up to 20 non-zero values."
print "A zero or blank entry ends the series."
[entryLoop] 'loop around until a zero entry or until index = 20
'get the user's name and age
print "Entry "; index + 1;
input name$
if name$ = "" then [endSeries] 'quit if name$ is blank
print "Age ";
input age
index = index + 1 'add one to index
names$(index) = name$ 'set the specified array item to be name$
numbers(index) = age 'set the specified array item to be age
total = total + age 'add entry to the total
if index = 20 then [endSeries] 'if 20 values were entered, exit loop
goto [entryLoop] 'go back and get another entry
[endSeries] 'entries are finished
'Set entryCount to index
entryCount = index
if entryCount = 0 then print "No Entries." : goto [quit]
print "Entries completed."
print
print "Here are the "; entryCount; " entries:"
print "-----------------------------"
'This loop displays each entered value in turn.
'Notice that we re-use the index variable. It
'can be confusing to use a new variable for each
'new loop.
for index = 1 to entryCount
print "Entry "; index; " is "; names$(index); ", age ";
numbers(index)
next index
'*** New code starts here ***
'Write the data into ages.dat
open "ages.dat" for output as #ages
for index = 1 to entryCount
print #ages, names$(index)
print #ages, numbers(index)
next index
close #ages
'*** New code ends here ***
'Now display the total and average value
print
print "The total age is "; total
print "The average age is "; total / entryCount
[quit]
end
Try running the program and enter a few names and ages. When the program
finishes executing, open the file with Notepad and you'll the data you entered.
It should look something like:
Tom Jones
52
Victor Krueger
39
Sue White
64
Let's see how our newly added code works.
1) First we open the file AGES.DAT with the OPEN statement. It is opened for
OUTPUT (writing) and its file handle is #ages.
open "ages.dat" for output as #ages
2) This sets up a FOR/NEXT loop.
for index = 1 to entryCount
3) Now we print a name and age, each on a separate line.
print #ages, names$(index)
print #ages, numbers(index)
4) Here's the back end of our FOR/NEXT loop. Loop back until index equals
entryCount.
next index
5) Now we will close AGES.DAT.
close #ages
Reading from a file
Now that we've written information to a disk file, we are going to read that
information back into our program. This is done using the INPUT statement. Just
as we saw PRINT used to display information in a window and to write information
to a disk file, INPUT can be used to get keyboard input, or to get information
from a disk file.
To read from a file, it must be opened using the INPUT mode. The OPEN statement
is used like so:
open "ages.dat" for input as #ages
Our INPUT statement for reading from a file looks a lot like the PRINT statement
above:
input #ages, var$
Notice we use the file handle, and then we specify a variable name to read into.
In a program that reads a list of items, an INPUT statement like the one above
would be placed inside of a loop. In this way each item in the file can be read
in turn and stored in an array.
An important point is that that we don't always know how many items have been
written to AGES.DAT. This means we don't know when to stop looping around and
reading items from the file. One solution is to add a PRINT statement to the
program that creates the file. This PRINT statement would write the number of
items at the start of the file, like so:
'Write the data into ages.dat
open "ages.dat" for output as #ages
print #ages, entryCount
for index = 1 to entryCount
print #ages, names$(index)
print #ages, numbers(index)
next index
close #ages
Then all we would need to do is read that number first, and then loop that many
times to read each name and age. I will tackle it from a different direction
though, because I want to introduce the EOF() function.
The EOF() function stands for End Of File. For a given file handle, it will
return 0 if we are not at the end of file, and -1 if we are at the end of file.
For example:
open "ages.dat" for input as #ages
if eof(#ages) = 0 then print "NOT AT END OF FILE"
close #ages
The above code would print NOT AT END OF FILE because we haven't read all the
way to the end of the file.
Here is a version of AGES.BAS that reads it's information from the file we
created above and uses EOF() to check for the end of file.
'AGES_IN.BAS
'Read names and ages from AGES.DAT, then total and average them.
'This version doesn't write the data back out to the file.
dim numbers(20)
dim names$(20)
print "AGES_IN.BAS"
print
print "Reading AGES.DAT..."
'open ages.dat
open "ages.dat" for input as #ages
[entryLoop] 'loop around until end of file or until index = 20
'test for the end of file
if eof(#ages) = -1 then [endSeries]
'get the user's name and age
input #ages, name$
input #ages, age
index = index + 1 'add one to index
names$(index) = name$ 'set the specified array item to be name$
numbers(index) = age 'set the specified array item to be age
total = total + age 'add entry to the total
if index = 20 then [endSeries] 'if 20 values were entered, exit loop
goto [entryLoop] 'go back and get another entry
[endSeries] 'entries are finished
'close ages.dat
close #ages
'Set entryCount to index
entryCount = index
if entryCount = 0 then print "No Entries." : goto [quit]
print "Entries completed."
print
print "Here are the "; entryCount; " entries:"
print "-----------------------------"
'This loop displays each entered value in turn.
'Notice that we re-use the index variable. It
'can be confusing to use a new variable for each
'new loop.
for index = 1 to entryCount
print "Entry "; index; " is "; names$(index); ", age ";
numbers(index)
next index
'Now display the total and average value
print
print "The total age is "; total
print "The average age is "; total / entryCount
[quit]
end
Challenge Exercise
Create a modified ARRAYS.BAS using the code below so that it keeps its list in a
disk file named ARRAYS.DAT. The program must read its list from ARRAYS.DAT
before asking for additional names. When the user is done
entering names, or if all the slots are filled, the list will be written to
ARRAYS.DAT before the program ends. See the source code below for some clues.
'ARRAYS2.BAS
'List handling with arrays and file input/output.
'This version stores more than 10 names.
dim names$(50) 'set up our array to contain 50 items
'Insert code that reads ARRAYS.DAT into the array names$.
[askForName] 'ask for a name
input "Please give me your name ?"; yourName$
if yourName$ = "" then print "No name entered." : goto [quit]
index = 0
[insertLoop]
'check to see if index points to an unused item in the array
if names$(index) = "" then names$(index) = yourName$ : goto [nameAdded]
index = index + 1 'add 1 to index
if index < 50 then [insertLoop] 'loop back until we have counted to 50
'There weren't any available slots, inform user
print "All ten name slots already used!"
goto [quit]
[nameAdded] 'Notify the name add was successful
print yourName$; " has been added to the list."
goto [askForName]
[quit]
'display all the entered names
print
print "Here is a list of the names entered:"
print "------------------------------------"
for index = 0 to 49
if names$(index) <> "" then print names$(index)
next index
'Insert code that saves the names$ array to ARRAYS.DAT.
end