Input and Output statements are required to allow the Pascal program to interact with both stored data and with the user of the program. The simplest commands are writeln which writes data to the specified output device, and readln which reads data from the specified input device. In each case, if no output device is specified, the output is written to or read from the default output device, usually the computer screen.
We have already used the writeln command extensively, in the program below we use both the writeln and readln commands together which converts farenheit to celsius and vice-versa.
Example
program temperature_conversion;
var celsius, farenheit : real;
var option : char;
begin
writeln ('Enter Option : ');
writeln ('C to convert Celsius to Farenheit ');
writeln ('F to convert Farenheit to Celsius ');
readln (option);
if ((option = 'c') OR (option = 'C')) then
begin
writeln ('Enter temperature in Celsius ');
readln (celsius);
farenheit := 32 + (celsius * 9/5);
writeln (celsius:4:2, ' Celsius is ',farenheit:4:2,' Farenheit equivalent');
end
else if ((option = 'f') OR (option = 'F')) then
begin
writeln ('Enter temperature in Farenheit ');
readln (farenheit);
celsius := (farenheit - 32) * 5 / 9;
writeln (farenheit:4:2, ' Farenheit is ',celsius:4:2,' Celsius equivalent');
end
end.
There are some items that we have used in this program that we have not used before :
It can be seen that the readln command takes a parameter of the variable into which the value typed at the screen is read. It is important that the variable type used is appropriate to the data to be input, otherwise your program may yield unpredictable results.
Although Pascal is not case sensitive in interpreting its commands and variable names, it is case sensitive in the case of the values that variables assume. Thus a character variable containing the value 'F' is not the same as a character variable containing the value 'f'. Hence the if clauses must check in each case if the user inputs his choice in either upper or lower case.
File Input/ Ouput
So far we have been reading from and writing to the default device, usually the computer screen. However, for file manipulation it is essential that we can create, write to and read from data files on the computer. There are some simple commands, variations on readln and writeln, which allow us to perform File I/O. The basic file manipulation commands are :
Comand
Action
Read
Reads a line from a file (Readln reads the line and moves to the next line).
Write
Writes a line to a file (Writeln writes the line and moves to the next line).
Assign
Assigns the physical name of a file to a file variable.
Rewrite
Resets the file pointer to the start of a file to be written to, overwriting any previous data in the file.
Reset
Resets the file pointer to the start of a file to be read from.
Append
Sets the file pointer to the end of a file where data is to be appended to that file
Close
Closes the specified file, flushing any related file buffers before closing it.
Eof
Checks for end-of-file condition
Creating a File
The following program creates an empty file 'c:\paddress.txt'. We will be using this address file for some programs later on where we write address information and read address information from the file. It is important that the file creation program be run only once, as, each time it is run, should the specified file already exist, it overwrites it with an empty file.
program createaddressfile;
{ }
{ Creates a blank address file and saves }
{ it as c:\paddress.txt }
{ }
var outfile : text;
begin
assign (outfile, 'c:\paddress.txt');
rewrite (outfile);
close (outfile);
end.
A few things to note in this program :
The declaration of the file variable in the var statement. Here the file to be used is identified to the compiler as a text file. The variable name, outfile, is the name by which the other file manipulation commands will refer to the file.
The assign command assigns a name to the file associated with the physical name and directory location of the file.
The rewrite command creates the file and resets the pointer to the start of the file. If the file already exists, the rewrite command will destroy any data already in the file.
The close command flushes the file buffer and closes the file. In this case, we have written no data to the file, so a file of the specified name, of zero bytes in size is created and saved in the specified directory.
Writing Data to a File
The program below is a simple contact database which stores four fields (name, addres, email address and telephone number). It takes the information input by the user from the screen, formats it, and writes it to file. The program introduces some new ideas which we discuss below.
program writeaddress;
{ sizes for the fields to be stored in the file }
const namesize = 30;
const addresssize = 30;
const telnosize = 30;
{ record structure for the file }
type
address_record = record
name : string[namesize];
address : string[addresssize];
email_address : string[addresssize];
telno : string[telnosize];
end;
var address_rec : address_record;
var outfile : text;
begin
{ open the file and prepare to append to existing records }
assign (outfile, 'c:\paddress.txt');
append (outfile);
{ get field data from the user }
write ('Enter Name : ');
readln (address_rec.name);
write ('Enter address for ',address_rec.name,' : ');
readln (address_rec.address);
write ('Enter Email address for ',address_rec.name,' : ');
readln (address_rec.email_address);
write ('Enter Telephone Number for ', address_rec.name,' : ');
readln (address_rec.telno);
{write the field data to the file }
with address_rec do
begin
write (outfile,name,',');
write (outfile,address,',');
write (outfile,email_address,',');
writeln (outfile,telno);
end;
close (outfile);
end.
There are some aspects of this program that we have not come across as yet :
Firstly, we have used comments in earlier programs delimited by "(*" and "*)". Comments can also be delimited with an opening "{" and a closing "}" as we use here.
The file will hold a series of records, and each record will hold a number of fields - name, address, email and telephone number. The type definition defines a record type called address_record. An address_record is a grouping of the contacts file fields which are each declared within the record type declaration. The string sizes are for each field are defined in the const declarations above
An instance of the address_record type is declared in the var section. The statement
var address_rec : address_record;
declares a variable called address_rec which is of the type address_record. When we manipulate the contact fields, it will be using the address_rec variable
The output file, outfile is declared as a text file. The variable outfile is associated with a physical file within the main body of the program using the assign statement. It is then opened in append mode, so any record added will be added after any existing records. It is important that the file exist for it to be opened in append mode, otherwise a runtime error will result.
We then read the variables from the screen into the variables in the address_rec structure. To reference or access individual fields within a structure, the form structure.subfield is used. An alternative to typing the structure name repeatedly, as we do in the group of readln statements, is to use the with construct, as we do when we are writing the fields to the file in the series of write and writeln commands. The with command, which uses a structure as its arguments, means that fields within that structure can be accessed or referenced without typing the full structure name. The with command uses a begin and an end to delimit where the with command holds scope.
In the block of write and writeln commands, we write the individual fields, delimiting each field with a comma so we can separate the fields when we are reading the record back in later. The data is written in a stream using the write command until the last field is written, when a writeln command is used to go to a new line for the next record. An alternative would be to write each field to a new line in the record, but using this approach creates a dependency between a knowledge of the program and the structure of the file. As we have it written here, each record stores a complete contact record, making it easier to separate the output file from the programs which manipulate it.
Finally, we close the output file using the close command, flushing any pending buffers to be written to the output file.
For the moment, every time a record is to be added to the address file, the program has to be invoked anew. The extension of this program to allow ongoing input is a simple addition to the program, but is left for a later section on looping and repetition.
Reading data from a file
So now we have the file 'c:\paddress.txt' which has been created in the program above and (assuming you have run the program once or more) contains some names and addresses. Now we need to write a program to read the contacts data from the file. The commands used are very similar in format and structure to those used for writing to the file. The program below reads right through the file and outputs the details of each record to the screen.
program readaddress;
{ sizes for the fields to be stored in the file }
const namesize = 30;
const addresssize = 30;
const telnosize = 20;
{ record structure for the file }
type
address_record = record
name : string[namesize];
address : string[addresssize];
email_address : string[addresssize];
telno : string[telnosize];
end;
var address_rec : address_record;
var infile : text;
var recstring : string[113];
var comma : integer;
begin
{ open the input file and read through all existing records }
assign (infile, 'c:\paddress.txt');
reset (infile);
while not (eof(infile)) do
begin
readln (infile, recstring);
{variable recstring now contains the complete record, so we }
{must parse it to extract the individual fields }
{ 1st field is name }
comma := pos(',',recstring); { find where the first field terminates }
address_rec.name := copy (recstring, 1, comma-1); { copy into address_rec.name }
delete (recstring, 1, comma); { delete the name section from recstring}
{ 2nd field is address }
comma := pos(',',recstring);
address_rec.address := copy (recstring, 1, comma-1);
delete (recstring, 1, comma);
{ 3rd field is email_address }
comma := pos(',',recstring);
address_rec.email_address := copy (recstring, 1, comma-1);
delete (recstring, 1, comma);
{ the remaining character in the string is the field telno }
address_rec.telno := recstring;
{ Print out the details }
with address_rec do
begin
writeln ('Name : ', name);
writeln ('Address : ', address);
writeln ('Email : ', email_address);
writeln ('Phone : ', telno);
writeln ('');
end; { end of with address_rec }
end; { end of while not(eof) }
writeln (' * * End-of-file reached * *');
close (infile);
end.
Most of the above program will be familiar - the record structure that we read into and the field sizes are the same as the record structure and field sizes we used to write to the paddress.txt file in the earlier file writing program. However, there are some new features to examine :
Each readln commmand used on the input file will read a complete record. We declare a variable recstring to hold this complete record. The string size for recstring allows for the maximum size of all of the constituent fields on the record and the field delimiting commas. The integer variable comma will be used to identify where the commas occur in the recstring variable so we can separate out the fields.
We assign the physical file to the file variable as before, but here we use the reset command to return a read pointer to the top of the file.
The while(not(eof)) command creates a loop delimited by the following begin and end. The loop executes the same command repeatedly until the condition specified in the while(condition) command evaluates to false . In this case we read through the file while we are not at the end-of -file(eof), printing each record out to screen as we read it. (More about while in the section on Repetition and Looping).
The pos command returns the location of the specified text in the specified field. In our case we know each record to contain three commas, delimiting four fields. We use this information to locate the comma, and read the text up to, but not including that comma, into the appropriate field. After copying the relevant section of the recfield variable to the appropriate record structure variable using the copy command, we delete that section from recfield using the delete command, and move onto the next field. The last field, address_rec.telno, does not terminate with a comma, and is the balance of the variable recfield once the email_address field has been deleted from recfield.
We then write out the details of the address_rec structure using a block of writeln commands. The writeln(''); command writes a blank line to screen between each record - this could also be achieved using just writeln; with no parameters.
Finally, once the end of file has been reached and the while loop terminates, we write a message to that effect to the screen and close the input file.