Category : Pascal Source Code
Archive   : PASTUT.ZIP
Filename : CHAP11.TXT

 
Output of file : CHAP11.TXT contained in archive : PASTUT.ZIP



Chapter 11
FILE INPUT/OUTPUT


FILES HANDLE SERIAL DATA
____________________________________________________________

One of the most common operations when using a computer is to
either read from, or write to a file. You are already
somewhat experienced in file handling from the last chapter,
because in computer terminology, the keyboard, terminal, and
printer are all classified as files. A file is any serial
input or output device that the computer has access to. Since
it is serial, only one piece of information is available to
the computer at any instant of time. This is in contrast to
an array, for example, in which all elements of the array are
stored internally and are all available at any time.


A SHORT HISTORY LESSON
____________________________________________________________

Several years ago computers were all large cumbersome machines
with large peripheral devices such as magnetic tape drives,
punch card readers, paper tape readers or punches, etc. It
was a simple task to assign the paper tape reader a symbol and
use that symbol whenever it was necessary to read a paper
tape. There was never more than one file on the paper tape
being read, so it was simply read sequentially, and hopefully
the data was the desired data. With the advent of floppy
disks, and hard disks, it became practical to put several
files of data on one disk, none of which necessarily had
anything to do with any of the other files on that disk. This
led to the problem of reading the proper file from the disk,
not just reading the disk.

Pascal was originally released in 1971, before the
introduction of the compact floppy disk. The original release
of Pascal had no provision for selecting a certain file from
among the many included on the disk. Each compiler writer had
to overcome this deficiency and he did so by defining an
extension to the standard Pascal system. Unfortunately, all
of the extensions were not the same, and there are now several
ways to accomplish this operation. There are primarily two
ways, one using the Assign statement, and the other using the
Open statement. They are similar to each other and they
accomplish the same end result.


BACK TO THE PRESENT TIME
____________________________________________________________

All of the above was described to let you know that we will
have a problem in this chapter, namely, how do we cover all

Page 11-1

File Input/Output

of the possible implementations of Pascal available? The
answer is, we can't. Most of what is covered in this chapter
will apply to all compilers, and all that is covered will
apply to the TURBO Pascal compilers, versions 3.0 through 5.x.
This tutorial is especially written for the TURBO Pascal
compilers, but you should be warned you will find differences
in Pascal implementations if you ever find a need to use a
different Pascal compiler someday. You may, for example, need
to use a mini-computer or a mainframe computer someday to
complete a programming assignment. When that happens, you
will find that the area of input/output control will probably
be the biggest difference in the implementations of Pascal.


READING AND DISPLAYING A FILE
____________________________________________________________

Examine the file READFILE.PAS for an ================
example of a program that can read a text READFILE.PAS
file from the disk. In fact it will read ================
itself from the disk and display it on the
video monitor. The first statement in the
program is the Assign statement. This is TURBO Pascal's way
of selecting which file on the disk will be either read from
or written to. In this case we will read from the disk. The
first argument in the Assign statement is the device specifier
similar to Lst used in the last chapter for the printer. We
have chosen to use the name Turkey for the device identifier,
but could have used any valid identifier. This identifier
must be defined in a var declaration as a TEXT type variable.
The next argument is the filename desired. The filename can
be defined as a string constant, as it is here, or as a string
variable.

The TEXT type is a predefined type and is used to define a
file identifier. It is predefined as a "file of char", so it
can only be used for a text file. We will see later that
there is another type of file, a binary file.

Now that we have a file identified, it is necessary to prepare
it for reading by executing a reset statement in line 9. The
Reset statement positions the read pointer at the beginning
of the file, ready to read the first piece of information in
the file. Once we have done that, data is read from the file
in the same manner as it was when reading from the keyboard.
In this program, the input is controlled by the while loop
which is executed until we exhaust the data in the file.


WHAT ARE THE "EOF" AND "EOLN" FUNCTIONS?
____________________________________________________________

The Eof function is new and must be defined. When we read
data from the file, we move closer and closer to the end,

Page 11-2

File Input/Output

until finally we reach the end and there is no more data to
read. This is called "end of file" and is abbreviated Eof.
Pascal has this function available as a part of the standard
library which returns FALSE until we reach the last line of
the file. When there is no more data to read left in the
file, the function Eof returns TRUE. To use the function, we
merely give it our file identifier as an argument. It should
be clear to you that we will loop in this program until we
read all of the data available in the input file.

The Eoln function is not used in this program but is a very
useful function. If the input pointer is anywhere in the text
file except at the end of a line, the Eoln returns FALSE, but
at the end of a line, it returns a value of TRUE. This
function can therefore be used to find the end of a line of
text for variable length text input.

To actually read the data, we use the Readln procedure, giving
it our identifier Turkey and the name of the variable we want
the data read into. In this case, we read up to 80 characters
into the string and if more are available, ignore them. You
should remember when we did this in the last chapter from the
keyboard input. We are using the same technique here except
we are reading from a file this time. Since we would like to
do something with the data, we output the line to the default
device, the video monitor. It should be clear to you by now
that the program will read the entire file and display it on
the monitor.

Finally, we Close the file Turkey. It is not really necessary
to close the file because the system will close it for you
automatically at program termination, but it is a good habit
to get into. It must be carefully pointed out here, that you
did not do anything to the input file, you only read it and
left it intact. You could Reset it and reread it again in
this same program. Compile and run this program to see if it
does what you expect it to do.


A PROGRAM TO READ ANY FILE
____________________________________________________________

Examine the next program READDISP.PAS for ================
an improved file reading program. This is READDISP.PAS
very similar except that it asks you for ================
the name of the file that you wish to
display, and enters the name into a 12
character string named Name_Of_File_To_Input. This is then
used in the Assign statement to select the file to be read,
and the file is reset as before. Lines 15 through 18 display
a header, and from that point on, the program is identical to
the last one with a few small additions. In order to
demonstrate the use of a function within the Writeln
specification, the program calls for the length of the input

Page 11-3

File Input/Output

string in line 23 and displays it before each line. The lines
are counted as they are read and displayed, and the line count
is displayed at the end of the listing.

You should be able to see clearly how each of these operations
is accomplished. Compile and run this program, entering any
filename we have used so far (be sure to include the .PAS
extension). After a successful run, enter a nonexistent
filename and see the I/O error.


HOW TO COPY A FILE (SORT OF)
____________________________________________________________

Examine the file READSTOR.PAS for an ================
example of reading from a file and writing READSTOR.PAS
to another one. In this program we ================
request an operator input for the filename
to read, after which we Assign the name to
the file and Reset it. When we reset the file however, we go
to a bit of extra trouble to assure that the file actually
exists.

Suppose we input a filename, and the file did not exist
because the file was actually missing, or because we entered
the filename wrong. Without the extra effort, the TURBO
Pascal runtime system would indicate a run-time error, and
terminate the program returning us to the operating system.
In order to make a program easier to use, it would be nice to
tell the operator that the file didn't exist and give him the
opportunity to try again with another file name. The method
given in lines 16 through 20 of this program will allow you
to do just that.


USING A COMPILER DIRECTIVE
____________________________________________________________

First you must disable the built in TURBO Pascal I/O checking
by inserting the compiler directive in line 16. This tells
the system to ignore any I/O errors from this point on and if
the file doesn't exist, the system will not abort when you
attempt to reset it in line 17. Another compiler directive
is given in line 18 to enable I/O checking again for the
remainder of the program.


WE DO OUR OWN FILE CHECKING
____________________________________________________________

If the file didn't exist and could not therefore be reset, we
have a problem because the program thinks the file is
available for use but it actually isn't. Fortunately, TURBO
Pascal has a built in variable, named IOResult, that informs

Page 11-4

File Input/Output

us of the result of each I/O operation. Following any I/O
operation, if this variable contains the value of zero, the
I/O operation was correct, and if it contains any other value,
the operation had some sort of error. In our case, we simply
compare it to zero to generate a boolean value, then based on
the boolean value we either give an error message and stop,
or perform the desired file operations.

It would be good programming practice to check all file
openings in this manner to allow the operator to recover from
a simple oversight or spelling error.

If the file was opened properly, then in line 21 through 24
we request a different filename to write to, which is assigned
to a different identifier. Note that the output file is not
checked for a valid opening as it should be. The statement
in line 24 is new to us, the Rewrite statement. This name
apparently comes from the words REset for WRITEing because
that is exactly what it does. It clears the entire file of
any prior data and prepares to write into the very beginning
of the file. Each time you write into it, the file grows by
the amount of the new data written.

Once the identifier has been defined, and the Rewrite has been
executed, writing to the file is identical to writing to the
display with the addition of the identifier being specified
prior to the first output field. With that in mind, you
should have no trouble comprehending the operation of the
program. This program is very similar to the last, except
that it numbers the lines as the file is copied. After
running the program, look in your default directory for the
new filename which you input when it asked for the output
filename. Examine that file to see if it is truly a copy of
the input file with line numbers added.

One word of caution. If you used an existing filename for the
output file, the file was overwritten, and the original
destroyed. In that case, it was good that you followed
instructions at the beginning of this tutorial and made a
working copy of the distribution disk. You did do that,
didn't you?

Compile and run this program two different ways, once with a
valid input filename that should run properly, and the second
time with an input filename that doesn't exist to prove to
yourself that the test actually does work correctly.


HOW TO READ INTEGER DATA FROM A FILE
____________________________________________________________

It is well and good to be able to read text from a file, but
now we would like to read other forms of data from a file.
First we will look at an example program to read data from a

Page 11-5

File Input/Output

text file, then later we will see an example program that
reads from a binary file.

Examine the program READINTS.PAS for an ================
example of reading data from a text file. READINTS.PAS
A text file is an ASCII file that can be ================
read by a text editor, printed, displayed,
or in some cases, compiled and executed.
It is simply a file made up of a long string of char type
data, and usually includes linefeeds, carriage returns, and
blanks for neat formatting. Nearly every file on the Tutorial
disk you received with this package is a text file. One
notable exception is the file named LIST.EXE, which is an
executable program file.

The example program has nothing new, you have seen everything
in it before. We have an assignment, followed by a reset of
our file, followed by four read and write loops. Each of the
loops has a subtle difference to illustrate the Read and
Readln statements. Notice that the same file is used for
reading four times with a Reset prior to each, illustrating
the nondestructive read mentioned a few paragraphs ago.

The file we will be using is named INTDATA.TXT and is on your
disk. You could display it at this time using the program
READDISP.PAS we covered recently. Notice that it is simply
composed of the integer values from 101 to 148 arranged four
to a line with a couple of spaces between each for separation
and a neat appearance. The important thing to remember is
that there are four data points per line.



READ AND READLN ARE SLIGHTLY DIFFERENT
____________________________________________________________

As variables are read in with either procedure, the input file
is scanned for the variables using blanks as delimiters. If
there are not enough data points on one line to satisfy the
arguments in the input list, the next line is searched also,
and the next, etc. Finally when all of the arguments in the
input list are satisfied, the Read is complete, but the Readln
is not. If it is a Read procedure, the input pointer is left
at that point in the file, but if it is a Readln procedure,
the input pointer is advanced to the beginning of the next
line. The next paragraph should clear that up for you.

The input data file INTDATA.TXT has four data points per line
but the first loop in the program READINTS.PAS requests only
three each time through the loop. The first time through, it
reads the values 101, 102, and 103, and displays those values,
leaving the input pointer just prior to the 104, because it
is a Read procedure. The next time through, it reads the
value 104, advances to the next line and reads the values 105,

Page 11-6

File Input/Output

and 106, leaving the pointer just prior to the 107. This
continues until the 5 passes through the loop are completed.

The loop in lines 19 through 22 contains a Readln procedure
and also reads the values 101, 102, and 103, but when the
input parameter list is satisfied, it moves the pointer to the
beginning of the next line, leaving it just before the 105.
The values are printed out and the next time we come to the
Readln, we read the 105, 106, and 107, and the pointer is
moved to the beginning of the next line. It would be good to
run the program now to see the difference in output data for
the two loops. Remember that the only difference is that the
first loop uses the Read procedure, and the second uses the
Readln procedure.

When you come back to the program again, observe the last two
loops, which operate much like the first two except that there
are now five requested integer variables, and the input file
still only has four per line. This is no problem. Both input
procedures will simply read the first four in the first line,
advance to the second line for its required fifth input, and
each will do its own operation next. The Read procedure will
leave the input pointer just before the second data point of
the second line, and the Readln will advance the input pointer
to the beginning of the third line. Run this program and
observe the four output fields to see an illustration of these
principles.


NOW TO READ SOME REAL VARIABLES FROM A FILE
____________________________________________________________

Examine the file named REALDATA.TXT supplied on your Pascal
Tutorial disk. You will see 8 lines of what appears to be
scrambled data, but it is good data that Pascal can read.
Notice especially line 4 which has some data missing, and line
6 which has some extra data.

Examine the program file READDATA.PAS ================
which will be used to illustrate the READDATA.PAS
method of reading real type data. ================
Everything should be familiar to you,
since there is nothing new here. The
Readln statement is requesting one integer variable, and three
real variables, which is what most of the input file
contained. When we come to the fourth line, there are not
enough data points available, so the first two data points of
the next line are read to complete the fourth pass through the
loop. Since the file pointer is advanced to the beginning of
the next line, we are automatically synchronized with the data
again. When we come to the sixth line, the last two data
points are simply ignored. Run the program to see if the
results are as you would predict.


Page 11-7

File Input/Output

If a Read were substituted for the Readln in line 14 of the
program, the file pointer would not be advanced to the
beginning of line 6 after the fourth pass through the loop.
The next attempt to read would result in trying to read the
value 0.0006 as an integer, and a run time error would result.
Modify the program, substituting a Read for the Readln in line
14, and see if this is not true.

It should be pointed out that TURBO Pascal 4.0 and 5.x both
require a digit both before and after the decimal point in all
data that is to be read in as real type data or it will be
flagged as a run-time error and the program will be halted.
The digits can be zero as they are in several places in the
example file but they must be there. If you are using TURBO
Pascal 3.0, the leading and trailing digits are not required.

That is all there is to reading and writing text files. If
you learn the necessities, you will not be stumbling around
in the area of input/output which is very intimidating to many
people. Remember to Assign, then Reset before reading,
Rewrite before writing, and Close before quitting. It is of
the utmost importance to close a file you have been writing
to before quitting to write the last few buffers to the file,
but it is not as important to close read files unless you are
using a lot of them, as there is an implementation dependent
limit of how many files can be open at once. It is possible
to read from a file, close it, reopen it, and write to it in
one program. You can reuse a file as often as you desire in
a program, but you cannot read from and write into a file at
the same time.


NOW FOR BINARY INPUT AND OUTPUT
____________________________________________________________

Examine the file BINOUT.PAS for an example ================
of writing data to a file in binary form. BINOUT.PAS
First there is a record defined in the ================
type declaration part composed of three
different variable types. In the var
part, Output_File is defined as a "file of Dat_Rec", the
record defined earlier. The variable Dog_Food is then defined
as an array of the record, and a simple variable is defined.

Any file assigned a type of TEXT, which is a "file of char",
is a text file. A text file can be read and modified with a
text editor, printed out, displayed on the monitor, etc. If
a file is defined with any other definition, it will be a
binary file and will be in an internal format as defined by
the Pascal compiler and may not be readable by any compiler
other than the one used to write it. Attempting to display
such a file will result in very strange looking gibberish on
the monitor.


Page 11-8

File Input/Output

When we get to the program, the output file is assigned a name
in line 15, and a Rewrite is performed on it to reset the
input pointer to the beginning of the file, empty the file,
and prepare for writing data into it. The loop in lines 18
through 22 simply assigns nonsense data to all of the
variables in the 20 records so we have something to work with.

We write a message to the display that we are ready to start
outputting data, then we output the data one record at a time
with the standard Write statement. A few cautions are in
order here. The output file can be defined to store any
simple variable type, integer, byte, real, or a record, but
the types cannot be mixed. The record itself however, can be
any combination of data including other records if desired,
but any file can only have one type of record written to it.

A Writeln statement is illegal when writing to a binary file
because a binary file is not line oriented. A Write statement
is limited to one output field per statement. This is not a
serious limitation since it is a simple matter to put one
Write statement in the program for each variable you wish to
write out to the file. It is important to Close the file when
you are finished writing to it.


WHY USE A BINARY FILE
____________________________________________________________

A binary file written by a Pascal program cannot be read by
a word processor, a text editor or any other application
program such as a database or spreadsheet, and it may not even
be readable by a Pascal program compiled by a different
companies compiler because the actual data structure is
implementation dependent. It can't even be read by a Pascal
program using the same compiler unless the data structure is
identical to the one used to write the file. With all these
rules, it seems like a silly way to output data, but there are
advantages to using a binary output.

A binary file uses less file space than a corresponding text
file because the data is stored in a packed mode. Since all
significant digits of real data are stored, it is more precise
unless you are careful to output all significant data to the
corresponding TEXT file. Finally, since the binary data does
not require formatting into ASCII characters, it will be
considerably faster than outputting it in TEXT format. When
you run this example program, it will create the file
KIBBLES.BIT, and put 20 records in it. Return to DOS and look
for this file and verify its existence. If you try to TYPE
it, using the DOS TYPE command, you will have a real mess on
your monitor because it does not contain char type data, but
that might be a good exercise.



Page 11-9

File Input/Output

READING A BINARY FILE
____________________________________________________________

BININ.PAS is another example program that =================
will read in the file we just created. BININ.PAS
Notice that the variables are named =================
differently, but the types are all
identical to those used to write the file
and they are in the same order. An additional line is found
in the program, the if statement. We must check for the "end
of file" marker to stop reading when we find it or Pascal will
list an error and terminate operation. Three pieces of
information are written out to verify that we actually did
read the data file in.

Once again, a few rules are in order. A Readln is illegal
since there are no lines in a binary file, and only one
variable or record can be read in with each Read statement.


FILE POINTERS, GET, AND PUT STATEMENTS
____________________________________________________________

File pointers and the Get and Put procedures are a part of
standard Pascal, but since they are redundant and therefore
not needed, they are not a part of TURBO Pascal. The standard
Read and Write procedures are more flexible, more efficient,
and easier to use. The use of Get and Put will not be
illustrated or defined here. If you ever have any need for
them, they should be covered in detail in your Pascal
reference manual for the particular implementation you are
using.

Pointers will be covered in detail in the next chapter of this
tutorial.


PROGRAMMING EXERCISES
____________________________________________________________

1. Modify READFILE.PAS so that after reading and displaying
the file, the file is reset, then read and displayed
again. This was suggested in the text.

2. Write a program to read the data from any text file, and
display it on the monitor with line numbers and the
number of characters in each line. Finally display the
number of lines found in the file, and the total number
of characters in the entire file. Compare this number
with the filesize given by the DOS command DIR.





Page 11-10


  3 Responses to “Category : Pascal Source Code
Archive   : PASTUT.ZIP
Filename : CHAP11.TXT

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/