


                                                       Chapter 22
                                              BINARY INPUT/OUTPUT


Any useful computer program must have a way to get data into it to
operate on, and a way to get the results out to the user.  In part
1 of this tutorial, we studied how to get text in and out of the
computer, now we will see how to get binary data in and out of the
computer.  Most of the binary input and output will be to or from
files because the data is always in a machine readable format, not
one that a human reader can easily comprehend.  A block of binary
data could be transmitted to a hardware device that is designed to
respond to the data, or a block of data could be input from a
hardware device reporting on some process.  A little more will be
said about that later.



BINARY DATA OUTPUT
_________________________________________________________________

Examine the program named BISEQOUT.ADA for an    ================
example of outputting binary sequential data.      BISEQOUT.ADA
Ada gives you three data input/output library    ================
packages that are defined in the LRM, and
required to be available with every Ada
compiler.  They are listed by package name as follows;

Text_IO - This is used for text Input/Output and is always in a
     sequential mode of operation.  Any file can be used for input
     or output, but not both.  (This package has been in use during
     most of this tutorial and was specifically described in
     chapter 14.)

Sequential_IO - This is used for binary Input/Output and is always
     in a sequential mode of operation.  Any file can be used for
     input or output, but not both.

Direct_IO - This is used for binary Input/Output and can be used
     in either a sequential or random mode of operation.  Any file
     can be used for input, output, or input and output.

You should refer to either your compiler documentation or the LRM
for the definition of these three packages.  All three are found
in chapter 14 of the LRM.  Spend a little time studying the
procedures and functions available with each to become familiar
with the capability of each package.  The knowledge you have gained
studying this tutorial to this point should enable you to
understand most of the specifications of these three packages.





                                                        Page 22-1

                                 Chapter 22 - Binary Input/Output


THE PACKAGE NAMED Low_Level_IO
_________________________________________________________________

There is another input/output package that may be available with
your compiler named Low_Level_IO.  This is not required by the LRM,
but if it exists, it will be used for machine dependent
input/output programming with your particular implementation.  If
it exists with your compiler, the description of how to use it will
be included with your documentation, and since it will be
completely different with each compiler, no attempt will be made
to explain its use here.



BACK TO BISEQOUT.ADA
_________________________________________________________________

Although this program does very little, there are several steps
that must be performed to output to a binary file.  They will be
taken in order, so follow along closely.  First we must tell the
system that we wish to use the external package Sequential_IO,
which we do using a with clause in line 4.  Next we define a record
type to illustrate one kind of data that can be output to the file,
and declare a variable of the record type in line 18.

In order to use the sequential input/output package, we must
instantiate a copy of it, because it is a generic package and
cannot be used directly.  We do this in line 15, using the data
type we wish to output to the file, then add the use clause in line
16 to make the new package readily available.  We need a file name
to use as our internal file name, and we define it in line 19, but
with a bit of difficulty because we have an overloaded file type
available.  We have made Text_IO available to illustrate the
problem, even though we don't use it in this program, and it
contains a type named FILE_TYPE.  The package named Seq_IO that we
have instantiated also contains a type named FILE_TYPE, the one we
wish to use.  In order to tell the system which one we want, we
must use the extended naming notation to differentiate between the
two types.  This is done in line 19 of the example program.  With
these steps, we are ready to begin the executable part of the
program.

In a manner similar to that used for text files which we studied
earlier, we create the file in line 23, in this case using the mode
Out_File since we wish to write to the file.  As you recall, this
also ties the internal name for the file to the external name we
have chosen, NAMEFILE.TXT, which must follow the conventions for
our particular Ada compiler and operating system.  If your
operating system is substantially different, you may need to change
this name.  We are finally ready to actually use the output file,
so we load some nonsense data into the declared record variable in
lines 25 and 26, then enter a loop where we will change the Age
field of the record in order to have some varying data to write to

                                                        Page 22-2

                                 Chapter 22 - Binary Input/Output

the file.  This will make it more useful when we read the data from
this file in another example program.



WRITING BINARY DATA TO THE FILE
_________________________________________________________________

We actually write data to the file in line 30, where we use the
procedure Write which is part of the instantiated package we named
Seq_IO earlier, but since we have defined Seq_IO in a use clause,
we do not need the qualifier "dotted" to the procedure name.  We
mention the internal file name to tell the system which file we
wish to write to, and the variable which we desire to output.  The
variable to be output must be of the type for which the package was
instantiated, resulting in a rule that all binary records output
to any given file must be of the same type.  Even though they must
be of the same type, they can be records of a variant record with
different variants.

After writing 100 binary records, we close the file in the manner
shown in line 33, and the program is complete.

We covered a lot of territory in the last few paragraphs, but it
is useful information we will need in the next few example
programs, and of course we will need it anytime we wish to actually
use a binary file.  It should be clear that we could open several
files, each storing a different data type, and write to them in any
order provided that we wrote the proper data type to each file.

The resulting file, named NAMEFILE.TXT, will be used to illustrate
binary reading in the next two programs, so it is imperative that
you compile and execute this program.  After running it, you will
find the file named NAMEFILE.TXT in the default directory of your
system, and if you attempt to look at it with a text editor, it
will have some very strange looking characters because it is a
binary file.  You will notice however, that much of it will be
readable because of the nature of the data selected for this file.



READING A BINARY FILE
_________________________________________________________________

The example program named BISEQIN.ADA             ===============
illustrates how to read from a binary file in a     BISEQIN.ADA
sequential mode.  Everything in the declaration   ===============
part of the program is identical to the last
program except for the instantiation of an
integer I/O package in line 15 for use later.

The only differences in the executable part is the use of the Open
procedure from the Seq_IO package, which uses the In_File mode of
file opening.  We can now read from the file we wrote in the last

                                                        Page 22-3

                                 Chapter 22 - Binary Input/Output

program, but we cannot write to it from this program.  We execute
a loop 100 times where we read a record from the binary file each
time through the loop, the record being identical to the record
used to write the binary file.  If the record is different in
structure or in data types, you may get anything upon reading, and
it probably will not appear to have anything to do with the
original data written, because the bytes will be mixed around.

All 100 elements are read in and those with the Age field greater
than or equal to 82 are displayed to illustrate that the data
really did get written.  Finally, the binary file is closed and the
program terminated.



WHAT ABOUT PORTABILITY?
_________________________________________________________________

Suppose you wrote the binary file with one Ada compiler, and
attempted to read it using a different compiler.  It would be
indeterminate whether or not it would work, because each
implementor is free to define the internal bit patterns of the
various types to fit his particular compiler.  Using such simple
fields as those in this illustration would lead to a very good
chance of portability, but using more elaborate records or arrays,
would almost certainly cause incompatibility problems.  The
solution to this problem is to read a file with the same compiler
that was used to write it.  Of course a file written in a text
format, using Text_IO, is portable and can be read with a different
system.

Compile and execute this program and verify that the data really
did get output as desired.  If you did not compile and execute the
last example program, you did not generate the file named
"NAMEFILE.TXT", and you cannot successfully execute this program.



RANDOM INPUT AND OUTPUT
_________________________________________________________________

Examine the file named BIRANDIO.ADA for an       ================
example of random input and output.  Random file   BIRANDIO.ADA
access means that we can output data to the      ================
file, or read data from the file just as if the
file were an array.  The elements of the file do
not have to be accessed in order.  We will illustrate all of this
in this example program.

The declaration part of this program should look familiar to you
since it is nearly identical to the last two example programs.  The
biggest difference is the use of the Direct_IO package instead of
the Sequential_IO package.  We instantiate a copy of this called
Ran_IO, and use it to declare the internal filename,

                                                        Page 22-4

                                 Chapter 22 - Binary Input/Output

My_In_Out_File.  Next, as part of the declaration part of the
program, we declare a function that will be used to output data in
a neat form for us.



READING FROM THE RANDOM FILE
_________________________________________________________________

Before we can do anything with the file, we must open it, and since
we intend to read from and write to this file, we open it with the
InOut_File mode.  Of course we use the internal filename we defined
in line 21, and the external filename we have already written to.
In line 38, we use the procedure Read, reading from the file we
have opened, and we read the data into the record variable named
Myself.  The thing that is really new here is the use of the number
37 as the third actual parameter of the procedure call.  This tells
the system that we wish to read the 37th record from the designated
file.  We use our Display_Record procedure to display the record
read, then tell the system that we wish to read record number 25,
and display it.  In line 42, we don't tell the system which record
we want to read explicitly, so it returns the next record, the
26th, which we display.



WRITING TO THE RANDOM FILE
_________________________________________________________________

We fill the three fields of the record variable with nonsense data
in lines 46 through 48, and write the modified record to records
91, 96, and 97.  We write to record 97 because we don't specify a
record and the system will default to the next successive record
number.  In line 53 we call the procedure Set_Index with the value
of 88 as the value to set, and as you may guess, it sets the record
pointer to 88, which is the next record that will be read by
default if no record number is stated.  The loop in lines 54
through 57 read and display all records from 88 through the last,
because we keep reading until we find an end of file.  You will see
when you compile and execute this program that we did modify
records numbered 91, 96, and 97.

You will find binary Input/Output to be very useful for temporary
storage of large amounts of data, but you must keep in mind that
any data you write using this technique may or may not be readable
by some other system.  For this reason, binary output should not
be used except for data that is meant to be read by another program
compiled with the same Ada compiler as the data generator.  Be sure
to compile and execute this program.






                                                        Page 22-5

                                 Chapter 22 - Binary Input/Output

PROGRAMMING EXERCISES
_________________________________________________________________

1.   Modify BISEQOUT.ADA to write the same data to two different
     files, except when Age is between 50 and 60.  During this
     range, one of the characters should be changed for one of the
     files.

2.   Modify BISEQIN.ADA to read both files output from exercise 1
     and list the differences in the two files.

3.   Combine BISEQOUT.ADA and BISEQIN.ADA in such a way that the
     file is written in one loop, then read back in and displayed
     in a successive loop.







































                                                        Page 22-6