CHAPTER 9

FILE HANDLING: A DATABASE


A key feature of the computer is the ability to store information, and to retrieve it at a later time. The information (data) has to be saved somewhere, which is called a file, and has to be under a name, which is called a filename. A program constantly interacts with the files to store, retrieve, modify or delete the data. Traditionally, a file that is used to store or retrieve data is called a data file or an input file. A data file may contain personal information such as the names of employees, their telephone numbers and salaries.

You may work interactively with a program and enter the data each time. However, when the input data becomes large, it is necessary to work with a data file rather than typing the data over and over each time. One example of a data file would be supermarket pricing, where a huge amount of data is manipulated. In today’s web engine, hundreds of files may have to be processed in order to complete a search. The advancement of the Internet has proportionally increased the number of files and their size. For any organization, data processing and data manipulation are essential operations. A database runs the day-to-day operations by adding new records, searching for particular record(s), modifying the existing records and generating reports. Due to the real-time demand of data, the efficiency of databases is subject to review and, as a result, a tremendous effort has been spent to secure their reliability.

WORKING WITH A DATA FILE In order to work with a data file, whether it is to be used to store data or retrieve data, the following steps need to be taken into consideration.

  1. Include the file stream in the header file section.
  2. Associate a name with the data file and specify its mode as to whether to output, append or input. This step will open the data file and get it ready.
  3. Use the associated file name throughout the program the same way cin and cout are used, except that with cin and cout data are handled by the console (keyboard and screen).
  4. Close the file when you are finished.






TO ACCESS A DATA FILE FOR INPUT To access a data file to input from, the following steps should be considered:

#include <fstream> using namespace std;

1) Include the file stream header file. ifstream fin("datafile.txt");

2) Associate an input file name with an input file stream for accessing the data file.

You may indicate explicitly the mode of file access as input:

ifstream fin("datafile.txt",ios::in);



As a convention, the name fin is used which stands for "file in" as the C++ word cin stands for "console in". 3) Use the associated file name to access the data the same way cin accesses the data, e.g. from the keyboard.

fin>>itemid>>itemprice;



fin.close( );

4) Close the file indicating that the data access is terminated.



EXAMPLE: ACCESSING THE INPUT DATA FILE The following program demonstrates how an input data file that is already created can be accessed. The input data file may have been previously created either by an editor (such as notepad) or by a program (see the following).





#include <fstream> #include<iostream> using namespace std; main(){ long int empid; int hoursworked; double hourlyrate, grosspay; ifstream fin ("employee.txt"); fin>>empid>>hoursworked>>hourlyrate; grosspay= hoursworked * hourlyrate; cout <<"EMPLOYEE'S ID IS "<<empid<<endl; cout <<"THE GROSS PAY IS "<<grosspay<<endl; return 0; }//MAIN

Figure 9.1a - Program to access the input data file and to compute gross pay.

1000001 48 25

EMPLOYEE'S ID IS 1000001 THE GROSS PAY IS 1200

Figure 9.1b -Input data file employee.txt for Figure 9.1a.

Figure 9.1c -Output of the program in Figure 9.1a with input data file in Figure 9.1b.





The above program only accesses one set of data since there is no loop performed. However, by looping, the entire data file can be accessed.

TO WRITE INTO A FILE: OUTPUT FILE To write into a file, or simply to create an output file, the following steps need to be considered: 1) Include the file stream header file.

#include<fstream> using namespace std;



2) Associate an output file name with the file stream. A data file with the given name will be created.

ofstream fout("datafile.out");





ofstream fout("datafile.out", ios::out);

You may indicate explicitly the mode of file access as output:

As a convention, the name fout is used which stands for "file out" as the C++ word cout stands for "console out". 3) Use the associated file name to output the data, the same way cout outputs the data to the screen, except that the data will be redirected to the file.

fout<<itemid<< " "<<itemprice;



4) Close the file indicating that the data access is terminated. fout.close( );

#include <fstream> #include<iostream> using namespace std; main(){ int empid,hoursworked; float hourlyrate, grosspay; ofstream fout ("salary.txt"); //associating fout with salary.txt for (int i=1; i<=5; i++){ //loop for 5 employees cout<<" ENTER THE EMPLOYEE'S ID "; //interactive data entries cin>>empid; cout<<" ENTER HOURS WORKED "; cin>>hoursworked; cout<<" ENTER THE HOURLY RATE "; cin>>hourlyrate; grosspay= hoursworked * hourlyrate; //compute grosspay fout<<empid<<" "<<hoursworked <<" "<<hourlyrate<<" " <<grosspay<<endl; //writing to a file }// FOR fout.close( ); return 0; }//MAIN

Figure 9.2a - Writing to a file





ENTER THE EMPLOYEE'S ID 10001 ENTER HOURS WORKED 45 ENTER THE HOURLY RATE 20 ENTER THE EMPLOYEE'S ID 10002 ENTER HOURS WORKED 44 ENTER THE HOURLY RATE 25 ENTER THE EMPLOYEE'S ID 10003 ENTER HOURS WORKED 48 ENTER THE HOURLY RATE 30 ENTER THE EMPLOYEE'S ID 10004 ENTER HOURS WORKED 48 ENTER THE HOURLY RATE 50 ENTER THE EMPLOYEE'S ID 10005 ENTER HOURS WORKED 40 ENTER THE HOURLY RATE 50

10001 45 20 900 10002 44 25 1100 10003 48 30 1440 10004 48 50 2400 10005 40 50 2000

Figure 9.2c -Output file named salary.txt

Figure 9.2b -Sample output for Figure 9.2a.

INPUT FROM KEYBOARD AS WELL AS INPUT FROM DATA FILE: SEARCH Most of today’s programs interact with the user and then access the data file to search and to perform the necessary operations. The standard input routine such as cin will access the keyboard (Standard Input File) in order to receive the input (Search Request) from the user. An external input file will be opened and then, repeatedly, data will be retrieved until a match has occurred or input data have been exhausted to the end (END OF FILE REACHED).

#include <fstream> #include<iostream> using namespace std; main(){ long int accountnumber, searchaccountnumber; double balance; ifstream fin ("account.txt"); cout<<"ENTER YOUR ACCOUNT NUMBER "; cin>>searchaccountnumber; while(fin>>accountnumber>>balance){ if(searchaccountnumber==accountnumber){ cout<<accountnumber<<" CURRENT BALANCE IS $"<<balance<<endl; return 1; } }//WHILE cout<<" NO MATCH FOR ACCOUNT "<<searchaccountnumber<<endl; return 0; }//MAIN

Figure 9.3a - Search for a datum in a data file

ENTER YOUR ACCOUNT NUMBER 21003 21003 CURRENT BALANCE IS $365.2

Figure 9.3c -Sample output for Figures 9.3a and 9.3b



The above program asks the user to enter the account number and then the program will repeatedly access the account file and try to match the account number. Upon succession, it will cout the balance, and exits the program. Otherwise, the program will eventually reach the end of the file, and at that moment the message " NO MATCH FOR ACCOUNT" will be displayed.

MODE OF OPENING A FILE A file can be opened according to the following ways (modes): A file can be opened as an input file so that data can be retrieved.

ifstream fin ("data.in",ios::in);



The default file mode for ifstream is ios::in

ifstream fin ("data.in"); //input stream



A file can be opened so that data can be written or output to it.

ofstream fout ("data.out",ios::out);



The default file mode for ofstream is ios::out

ofstream fout ("data.out");



In addition a file can be for output by adding (appending) data to the end of the existing file.

ofstream fout ("data.out",ios::app);



A file can be for both input and output ios::in | ios::out

fstream fout ("data.dat", ios::in|ios::out);



WHAT IS A DATABASE (dbase) Manipulating data (information) plays an important role in any organization today. In order to manipulate the data, information has to be stored, retrieved, modified or deleted. At any moment new data can be added to a file, or existing information can be retrieved, modified or even deleted. Instead of one file there might be several files needed to store information as well as to interact with other files (file processing). The notion of data manipulation where data may be stored, retrieved, modified or even deleted is called a database. In addition, there are times when it is necessary to generate reports based on a certain request or computations from the database.

A JOURNEY FROM BIT TO DATABASE Computer information is represented in binary form using a bit. Each bit contains a value which is either zero or one. Eight bits represent a byte. Depending on the system one or two bytes represent a character. Several characters form a field or a string. One or more fields make up a record. Multiple records build a stream or a file. Finally several files create a database. However this naming convention may vary slightly, a string may represent the whole file or a database may contain only a single file.

BUILDING A SIMPLE DATABASE: Create, Display and Search The following program illustrates how easily you can build a simple database by putting a few functions together. For the sake of simplicity, the database program will add, display and search the data immediately, with data modification and deletion performed later. In writing this program, the concern is simplicity rather than efficiency (speed of program or saving space). The three functions for this database are myappend() to add a record to the end of data file, mydisplay() to display entire records, and mysearch() to search for a particular record.

#include<iostream> #include<fstream> #include<iomanip> #include<string.h> #include<cstdlib> using namespace std; myappend(char personname[],char phone[]){ ofstream fout("directory.in",ios::app); cout<<"ENTER PERSON NAME "; cin>>personname; cout<<"ENTER THE PHONE "; cin>>phone; fout<<personname<<setw(20)<<phone<<endl; return 0; }//MYAPPEND mysearch(char personname[],char phone[]){ char searchname[20]; ifstream fin("directory.in",ios::in); cout<<"ENTER THE SEARCH NAME "; cin>>searchname; while(fin>>personname>>phone){ if(strcmp(searchname,personname)==0){ cout<<"THE PHONE IS "<<phone<<endl<<endl; return 1; }//IF }//WHILE cout<<"NAME NOT FOUND "<<endl; return 0; }//MYSEARCH mydisplay(char personname[],char phone[]){ ifstream fin("directory.in"); while(fin>>personname>>phone){ cout<<"PERSON NAME IS "<<personname<<endl; cout<<"PHONE IS "<<phone<<endl;}//WHILE return 0; }//MYDISPLAY main(){ char option; char personname[20],phone[20]; cout<<"SELECT ONE OF THE FOLLOWING "<<endl; while(1){ cout<<"TYPE 1 TO INSERT "<<endl; cout<<"TYPE 2 TO DISPLAY "<<endl; cout<<"TYPE 3 TO SEARCH "<<endl; cout<<"TYPE # TO QUIT "<<endl; cin>>option; if(option=='1') myappend(personname,phone); else if(option=='2') mydisplay(personname,phone); else if(option=='3') mysearch(personname,phone); else if(option=='#') {cout<<"BYE "<<endl; exit(1);} }//WHILE return 0;

Figure 9.4a - A simple directory database

}//MAIN

SELECT ONE OF THE FOLLOWING TYPE 1 TO INSERT TYPE 2 TO DISPLAY TYPE 3 TO SEARCH TYPE # TO QUIT 1 ENTER PERSON NAME Xiaolan ENTER THE PHONE (718)763-8339 TYPE 1 TO INSERT TYPE 2 TO DISPLAY TYPE 3 TO SEARCH TYPE # TO QUIT 3 ENTER THE SEARCH NAME Ebrahimi THE PHONE IS (516)356-2863

TYPE 1 TO INSERT TYPE 2 TO DISPLAY TYPE 3 TO SEARCH TYPE # TO QUIT # BYE



Ebrahimi (516)356-2863 Walter (516)372-4874 Tri (718)282-2872





Figure 9.4b -File named directory.in in the program of Figure 9.4a.

Figure 9.4c -Sample output for Figures 9.4a. and 9.4b













HOW THE CONTENT OF A SEQUENTIAL FILE CAN BE MODIFIED OR DELETED A sequential file is like a cassette tape; one must scan from the beginning to get to a specific location. In order to change an item in the file, the content of the existing file has to be copied into a new file until the location of the modification is reached. At that moment, the modified data are copied to the file. Afterward, the remaining content of the old file will be copied to the new file. The deletion of an item from the file is similar to a modification, except that the item-to-be-deleted will not be copied to the new file. The difference between modification and deletion here is that for deletion, all the content of the file is copied except the search item, while in modification all the content is copied except the search item, but this is followed by the inclusion of a new item. However, after the copy completion there would be two files, one old file and one new file with the change. In order to make the program ready for the next round of operation, the old file has to be deleted and the new file has to be renamed to be the original file, which is done with a system call to the operating system.

ACCESS SYSTEM COMMANDS OF THE OPERATING SYSTEM: DEL and RENAME

The system commands of an operating system can be accessed through the use of a function by inclusion of the standard library. For example, in a Microsoft environment system, the commands "del" and "rename" can be used accordingly to delete and rename a file.

#include <cstdlib> using namespace std; system("del directory.in"); system("rename newdirectory.in directory.in");



Similarly, in the Unix or Linux operating system, the commands rm and mv can be accessed by the following system function.

system("rm directory.in");

system("mv newdirectory.in directory.in");



The following program demonstrates the use of system commands to delete and rename a file. #include<cstdlib> #include<fstream> #include<iostream> using namespace std; void main(){ ofstream fout ("file.dat",ios::out); int x; for( x=100;x<105;x++){fout<<x<<endl; }// creating the file by inserting a value fout.close(); ifstream fin ("file.dat",ios::in); ofstream outfile("newfile.dat",ios::out); while(fin>>x){ outfile<<x<<endl; } //copying the entire file.dat to newfile.dat outfile.close(); fin.close(); system ("del file.dat"); // for Unix use system("rm file.dat"); system("rename newfile.dat file.dat");// renaming newfile.dat to file.dat // for Unix system("mv newfile.dat file.dat"); outfile.close(); //to view the new file fin.open("file.dat"); while(fin>>x){cout<<x<<endl; } //Displaying the new content of file.dat }//MAIN

Figure 9.5a - Using the system command to delete and rename a file





100 101 102 103 104

Figure 9.5b - Output of Figure 9.5a



MODIFY A FILE: EXAMPLE

The following program illustrates how a file can be modified by copying the file to a new file, excluding the old data and including the new data. The drawback is that for each modification a complete new file must be created and the old file has to be deleted so that you can work with the new one.

#include<iostream> #include<fstream> #include<cstdlib> using namespace std; main(){ int number,modifynumber,i; int found =0; //creating a file with 5 numbers ofstream fout("file.in",ios::out); cout<<"ENTER 5 NUMBERS:"<<endl; for(i=1;i<=5;i++){ cin>>number; fout<<number<<endl; }// FOR fout.close(); cout<<"ENTER A NUMBER TO MODIFY:"; cin>>modifynumber; ifstream fin("file.in",ios::in); fout.open("temp.out",ios::out); //fout is already declared i=0; while((i<=5) ){ fin>>number; if ((modifynumber==number) && (found ==0)){ cout<<"ENTER A NEW NUMBER:"; cin>>modifynumber; fout<<modifynumber<<endl;found=1; }//IF else fout<<number<<endl; i++; }//WHILE fin.close(); //close the files fout.close(); system("del file.in"); system("rename temp.out file.in"); //display to test the modify file.in fin.open("file.in",ios::in); cout<<"THE CONTENT OF FILE IS:"<<endl; for(i=1;i<=5;i++){ fin>>number; cout<<number<<endl; }// FOR fin.close(); return 0; }//MAIN

Figure 9.6b - Output of Figure 9.6a











A COMPLETE BASIC DATABASE: INCLUSION OF MODIFY AND DELETE The program below puts together four functions to perform an essential part of a database, namely the insertion of a record, the search for a specific record, the modification of a record and finally, the deletion of a record. The program builds a simple telephone directory with two fields: people names and telephone numbers. However, other fields, such as addresses, can be added without much burden to the program. Each function works independently by opening a file for the purpose of writing to, or reading from it. When it comes to modification and deletion, the strategy for this program is to create a temporary file and to copy the entire file except the unwanted record. In the case of modification, a new record will be placed in place of the unwanted record. Analogous to this would be to erase a song from a cassette tape filled with songs. To play it safe, it is necessary to get another blank cassette and copy all the songs up to the unwanted song (don’t copy) and to copy the rest after. This will delete the unwanted song by not copying it. However, in the case of modification, a new song is placed instead. After the completion of the task, the old tape should be thrown out and the new tape should be labeled as the old tape. In the program these tasks are performed by system commands such as delete and rename in DOS mode (rm and mv in Unix). Note that the variable "option" is declared a "char", so that alphanumeric characters for both digit and character are covered. In this case it is possible to use the character "q" to quit the program. To check how your compiler reacts in different situations, change the option from char to integer, and run the program with different input including a character.

Note that the function mymodify and mydelete both use mysearch, although for simplicity this has not been done. It would be a good practice for you to improve the above functions to call the search and to share the code.

#include<fstream> #include<iomanip> #include<string.h> #include<cstdlib> #include<iostream> using namespace std; myappend(char personname[],char phone[]) { ofstream fout ("directory.in", ios::app); cout<<"ENTER PERSON NAME "; cin>>personname; cout<<"ENTER THE PHONE "; cin>>phone; fout<<setw(20)<<personname<<setw(20)<<phone<<endl; fout.close(); return 0; }//MYAPPEND mysearch(char personname[], char phone[]){ char searchname[20]; ifstream fin("directory.in"); cout<<"ENTER THE SEARCH NAME "; cin>>searchname; while (fin>>personname>>phone){ if(strcmp(searchname,personname)==0){ cout<<"THE PHONE IS "<<phone<<endl<<endl; return 1;}//IF }//WHILE cout<<"NAME NOT FOUND "<<endl<<endl; fin.close(); return 0; }//MYSEARCH mydisplay(char personname[], char phone[]){ ifstream fin ("directory.in"); while (fin>>personname>>phone){ cout<<"PERSON NAME IS "<<personname<<endl<<endl; cout<<"PHONE IS "<<phone<<endl<<endl; }//WHILE fin.close(); return 0; }//MYDISPLAY mymodify(char personname[], char phone[]){ char searchname[20];char newphone[14];int found = 0; ifstream fin("directory.in"); ofstream fout ("newdirectory.in"); cout<<"ENTER THE SEARCH NAME "; cin>>searchname; while (fin>>personname>>phone){ if(strcmp(searchname,personname)==0){ cout<<"ENTER THE NEW PHONE NUMBER"<<endl; cin>>newphone; fout<<setw(20)<<personname<<setw(20)<<newphone<<endl; found=1;}//IF else fout<<setw(20)<<personname<<setw(20)<<phone<<endl; }//WHILE if (found ==0) cout<<"NAME NOT FOUND "<<endl<<endl; else if (found==1){ fin.close();fout.close(); system("del directory.in"); system("rename newdirectory.in directory.in" ); }//ELSE return 0; }//MYMODIFY mydelete(char personname[], char phone[]){ char searchname[20]; int found = 0; ifstream fin("directory.in"); ofstream fout ("newdirectory.in"); cout<<"ENTER THE SEARCH NAME "; cin>>searchname; while (fin>>personname>>phone){ if(strcmp(searchname,personname)==0) found=1; else fout<<setw(20)<<personname<<setw(20)<<phone<<endl; }//WHILE if (found ==0) cout<<"NAME NOT FOUND "<<endl<<endl; else if (found ==1){ fin.close();fout.close(); system("del directory.in"); system("rename newdirectory.in directory.in" );}//ELSE return 0; }//MYDELETE main(){ char option; char personname[15], phone[14]; cout<<"SELECT ONE OF THE FOLLOWING "<<endl; while (1){ cout<<"TYPE 1 TO INSERT "<<endl; cout<<"TYPE 2 TO DISPLAY "<<endl; cout<<"TYPE 3 TO SEARCH "<<endl; cout<<"TYPE 4 TO MODIFY"<<endl; cout<<"TYPE 5 TO DELETE "<<endl; cout<<"TYPE # TO QUIT "<<endl<<endl; cin>>option; switch(option){ case '1': myappend(personname, phone); break; case '2': mydisplay(personname, phone); break; case '3': mysearch(personname, phone); break; case '4': mymodify(personname, phone); break; case '5': mydelete(personname, phone); break; case '#': cout<<"BYE "<<endl; exit(1); break;}//SWITCH }//WHILE return 0; }//MAIN



Ebrahimi (516)356-2863 Walter (516)372-4874 Tri (718)282-2872 Xiaolan (718)336-7368





Figure 9.7b -File named directory.in









Figure 9.7c -Sample output of the program in Figure 9.7a





OPENING A FILE: PROBLEMS When opening a file, there are several problems that you should consider. You cannot just assume that a file is going to be opened for use and that everything will be all right.What happens when the file that you are trying to access for input does not exist, is in another directory, or is not readable? Similarly, you cannot open a file to write if a restriction is assigned to the file mode, for example, a restriction indicating that you cannot create (ios::nocreate) the file if the file already exists or that you cannot replace the file if the file already exists (ios::noreplace). Other problems may arise connected with the operating system, such as an indication that no more files can be created or that the size of the file exceeds the limit. A program should also be able to consider an error message or be able to handle an exception if such an error has occurred.

#include <iostream> #include <fstream> #include <cstdlib> using namespace std; void main( ){ int id; ifstream fin ("test.in",ios::nocreate); if(!fin){ cerr<<"Problem with opening the file"<<endl; exit(1); }//IF while( fin>>id) cout<<id<<endl; }//MAIN

Figure 9.8b -Output of Figure 9.8a



Similarly if (!fin) can be used instead of if (fin==NULL).

if(!fin) cerr<< "Problem with opening the file"<<endl;



For more error-checking and exception-handling the commands try, throw, and catch can be used. The throw keyword indicates that an exception has occurred. The exception handling options will be discussed more in depth in the subsequent chapters.

FILE MODE AND ERROR-CHECKING What if a file is opened for input but the file does not exist in the indicated directory? What if a file is opened for output but the file already exists and you do not want to replace it? The following examples show situations when a file needs to be checked.

ifstream infile("datafile.in", ios::in|ios::nocreate); if (!infile) cerr<<"ERROR-FILE DOES NOT EXIST"<<endl;







In the example above the file has been opened for input. However, if the file does not exist, the file opening will fail and will not create a file.

In the following example the file has been opened for output. However, if the file already exists, there will be a failure. By default, ios::out will replace the existing file and wipe out its contents.

ofstream outfile("datafile.dat", ios::out|ios::noreplace); if (!outfile) cerr("ERROR-FILE ALREADY EXIT -CAN’T REPLACE"<<endl;







THE DIFFERENCE BETWEEN cerr AND cout You may have realized that cerr (console error) is used instead of cout. Use of cerr indicates that the display is an error message and, in case of redirection to file, cerr would not be redirected but will be displayed on screen.

PROBLEM WITH A SEQUENTIAL FILE: SOLUTIONS For every change in the sequential file, the entire file has to be copied to a new file. Obviously, with a large file this is very time-consuming. Thus, two solutions have been proposed.

1) Use of Random Access File: Instead of moving the file pointer from the beginning to the end, move and place the file pointer to the desired spot (BYTE) in the file so that particular information can be retrieved or stored. Note that the way data is originally stored plays a key role in this concept.

2) Use of arrays Copy (Dump) the entire file into arrays and then work with the arrays. At the end, or wherever it is necessary, the entire array is copied back into the file. However, this method may create problems of its own.

FILE WITH RANDOM ACCESS: seekg( ) and seekp( )

Having the freedom of going randomly anywhere in a file is the main theme of the Random Access file-handling technique. In order to retrieve the data from a file (seekg) or store the data to a file(seekp), a file indicator can be positioned (seek) at the desired place.

A file indicator can be positioned relative to any of the three file positions: beginning, current and end, as shown with the function seekg( ) and seekp( ).



ios::beg

ios::cur

ios::end





For example: seekp(-40, ios::cur); will seek put back 40 bytes (retreat -40 characters ) from the current position of the file indicator, making the file ready to store the data at that position. Similarly, seekg(100,ios::beg); will seek get (advance) the file indicator 100 bytes from the beginning of the file, making the file ready for the next reading operation.

#include<fstream> #include<iostream> #include<cstdlib> using namespace std; main(){ fstream finout("file.dat",ios::in | ios::out); int i,deletenumber,number; //creating a file cout<<"Creating a file with 5 values 1-->5 "<<endl; for(i=1;i<=5;i++) { finout<<i<<endl; cout<<i<<endl; }// FOR finout.close(); //closing file.in cout<<"Please enter a number to delete 1-->5 "; cin>>deletenumber; finout.open("file.dat",ios::in | ios::out); //re-open the file.in while(finout>>number){ if(number==deletenumber){ if(number==1){ finout.seekp(0,ios::cur); finout<<" "<<endl; cout<<"deleted... "<<number<<endl;}//IF else{ finout.seekp(0,ios::cur); finout<<" "<<endl; cout<<"deleted... "<<number<<endl; }//ELSE }//IF }//WHILE finout.close(); finout.open("file.dat",ios::in); cout<<"The new file is "<<endl; //display the file.in for(int j=0; j<4; j++){ finout>>number; cout<<number<<endl; }//WHILE return 0; }//MAIN

Figure 9.9b - Output of Figure 9.9a



RANDOM ACCESS AND FILE STRUCTURE The seek function enables the file indicator anywhere across the file, but how will this help to retrieve a specific information (field, or a record)? One way to make this possible is to give each piece of data, whether a field or record, a fixed size through the file and use this knowledge to maneuver the file. For example, choosing the size of each data as 4 bytes, SIZE=4; seekg(SIZE*10, ios::beg); will place the indicator on the 10th data for retrieval purposes. Similarly, SIZE=4; seekp(SIZE*10, ios::beg); will place the file indicator on the 10th data for storing data. At that point, whatever data exist will be overwritten.



FAST ACCESS OF A RECORD Random access can speed up the access if each record or field has a fixed length and each employee has a unique key, such as an employee id number. For example, if each record contains 100 bytes and the storing of each employee is done by the order of his or her id, access will become much faster if it is done sequentially. The following program accesses an employee record randomly. Similarly, the modification is done at the spot word at a given position of a given file.

#include <fstream> #include <iomanip> #include <cstdlib> #include <iostream> using namespace std; main(){ const int MAXRECSIZE =50; int accountid, searchaccountid; char name[15]; double balance; fstream outinfile ("file.dat", ios::in| ios::out); for (int i=0; i<3; i++){ cout<<"WHAT IS THE ACCOUNT ID: ENTER 0 TO 100"<<endl; cin>>accountid; cout<<"ENTER CUSTOMER NAME:"; cin>>name; cout<<"ENTER BALANCE:"<<endl; cin>>balance; outinfile.seekp(accountid*MAXRECSIZE, ios::beg); outinfile <<setw(10)<<accountid<<setw(20)<<name<<setw(20)<<balance<<endl; }// FOR cout<<" SEARCH ACCOUNT NUMBER: ENTER 0 TO 100: "<<endl; cin>>searchaccountid; outinfile.seekg(searchaccountid*MAXRECSIZE, ios::beg); outinfile>>accountid>>name>>balance; cout <<setw(10)<<accountid<<setw(20)<<name<<setw(20)<<balance<<endl; return 0; }//MAIN

Figure 9.10a - Fast access to a record

WHAT IS THE ACCOUNT ID: ENTER 0 TO 100 10 ENTER CUSTOMER NAME:James ENTER BALANCE: 367.50 WHAT IS THE ACCOUNT ID: ENTER 0 TO 100 20 ENTER CUSTOMER NAME:Smith ENTER BALANCE: 2000.43 WHAT IS THE ACCOUNT ID: ENTER 0 TO 100 30 ENTER CUSTOMER NAME:Jones ENTER BALANCE: 6543.87 SEARCH ACCOUNT NUMBER: ENTER 0 TO 100: 20 20 Smith 2000.43



Figure 9.10b - Output of Figure 9.10a



TEXT FILES VERSUS BINARY FILES: DEFAULT VERSUS ios:: binary A file can be opened as a text or as a binary in C++. The difference between text and binary depends on the conversion of certain characters in the text file. A text file is line- structured, as a sequence of ASCII code, while a binary file is a sequence of bytes. For example, in the text file the number 123 is written as ASCII 1, ASCII 2 and ASCII 3 instead of the binary value of 123.

Moreover, depending on the operating system, certain characters have more than one code. For example, in MS-DOS a new line ‘\n’ is represented by two codes: carriage return (CR ASCII 13) and line feed (LF ASCII 10). By contrast, in UNIX the new line is represented by a single-character line feed. Therefore, when writing to a file in a text file whether a new line ‘\n’ has to be converted to one character or two characters depends on the operating system. In a binary file there would be no conversion, and data will be written as they are. A file by default is a text file. To be a binary file, it must set as it opens for input or output. For example,

ofstream fout("data.out", ios::binary);



Using a text editor it is possible to view a text file. To view a binary file with the text editor, such as a notepad, is not possible.

#include<fstream> #include<cstdlib> #include<iomanip> #include<iostream> using namespace std; main(){ fstream finout("file.in",ios::in |ios::out | ios::binary); int i,modifynumber,n; //creating a file cout<<"Creating a file with 5 values 1-->5 "<<endl; for(i=1;i<=5;i++){ finout<<i<<endl; cout<<i<<endl; }// FOR finout.seekg(0,ios::beg); //bring it back to the beginning cout<<"Please enter a number to modify "; cin>>modifynumber; while(finout>>n){ if(modifynumber==n){ cout<<"Please enter a new number (0-9)"; cin>>modifynumber; finout.seekp(-1,ios::cur); finout<<modifynumber<<endl; break; }//IF }//WHILE finout.close(); finout.open("file.in",ios::in); cout<<"The new file is "<<endl; //display the file.in for(int j=0; j<5; j++){ finout>>n; cout<<n<<endl; }// FOR return 0; }//MAIN

Figure 9.11a - Binary file

Creating a file with 5 values 1-->5 1 2 3 4 5 Please enter a number to modify 5 Please enter a new number (0-9)9 The new file is 1 2 3 4 9

Figure 9.11b - Output of Figure 9.11a













TELEPHONE DIRECTORY & RANDOM ACCESS: seekp( ) MODIFY AND DELETE The following Telephone Directory program uses seekg( ) function to reposition the file indicator in order to write-over the modified information or replace with blank for the deletion operation.

#include<fstream> #include<iostream> #include<iomanip> #include<string.h> #include<cstdlib> using namespace std; fstream foutin("directory.dat",ios::app | ios::in); myappend(char personname[],char phone[]) { foutin.close(); foutin.open("directory.dat",ios::app); cout<<"ENTER PERSON NAME "; cin>>personname; cout<<"ENTER THE PHONE "; cin>>phone; foutin<<setw(20)<<personname<<setw(20)<<phone<<endl; return 0; }//MYAPPEND mysearch(char personname[], char phone[]){ foutin.close(); foutin.open("directory.dat",ios::in); char searchname[20]; cout<<"ENTER THE SEARCH NAME "; cin>>searchname; while (foutin>>personname>>phone){ if(strcmp(searchname,personname)==0){ cout<<"THE PHONE IS "<<phone<<endl<<endl; return 1; }//IF }//WHILE cout<<"NAME NOT FOUND "<<endl<<endl; return 0; }//MYSEARCH mydisplay(char personname[], char phone[]){ foutin.close(); foutin.open("directory.dat",ios::in); while (foutin>>personname>>phone){ cout<<"PERSON NAME IS "<<personname<<endl<<endl; cout<<"PHONE IS "<<phone<<endl<<endl; }//WHILE return 0; }//MYDISPLAY mymodify(char personname[], char phone[]){ char searchname[20]; int save=0; foutin.close(); foutin.open("directory.dat",ios::in); ofstream fout ("newdirectory.dat",ios::out); cout<<"ENTER THE SEARCH NAME "; cin>>searchname; while (foutin>>personname>>phone){ if(strcmp(searchname,personname)==0){ cout<<"ENTER THE NEW PHONE NUMBER"<<endl; cin>>phone; fout<<setw(20)<< personname<<setw(20)<<phone<<endl; save=1; }//IF else fout<<setw(20)<<personname<<setw(20)<<phone<<endl; }//WHILE if(save==1){ foutin.close(); fout.close(); system("del directory.dat"); system("rename newdirectory.dat directory.dat"); cout<<"The phone has been modified..."<<endl; }//IF else cout<<"NAME NOT FOUND "<<endl<<endl; foutin.open("directory.dat",ios::in); return 0; }//MYMODIFY mydelete(char personname[], char phone[]){ char searchname[20]; int deleted; foutin.close(); foutin.open("directory.dat",ios::in); ofstream fout ("newdirectory.dat",ios::out); cout<<"ENTER THE NAME TO DELETE "<<endl; cin>>searchname; while (foutin>>personname>>phone){ if(strcmp(searchname,personname)==0){ cout<<personname<<" HAS BEEN DELETED..."<<endl; deleted=1; }//IF else fout<<setw(20)<<personname<<setw(20)<<phone<<endl; }//WHILE if(deleted==1){ foutin.close(); fout.close(); system("del directory.dat"); system("rename newdirectory.dat directory.dat"); }//IF else cout<<"NAME NOT FOUND "<<endl<<endl; foutin.open("directory.dat",ios::in); return 0; }//MYDELETE main(){ char option; char personname[15], phone[14]; cout<<"SELECT ONE OF THE FOLLOWING "<<endl; while (1){ cout<<"TYPE 1 TO INSERT "<<endl; cout<<"TYPE 2 TO DISPLAY "<<endl; cout<<"TYPE 3 TO SEARCH "<<endl; cout<<"TYPE 4 TO MODIFY"<<endl; cout<<"TYPE 5 TO DELETE "<<endl; cout<<"TYPE # TO QUIT "<<endl<<endl; cin>>option; if (option=='1') myappend(personname, phone); else if (option=='2') mydisplay(personname, phone); else if (option=='3') mysearch(personname, phone); else if (option=='4') mymodify(personname, phone); else if (option=='5') mydelete(personname, phone); else if (option =='#') { cout<<"BYE "<<endl; exit(1); }//ELSE IF }//WHILE return 0; }//MAIN

Figure 9.12c -Sample output of the program in Figure 9.12a



A BINARY FILE ACCESS WITH FUNCTIONS read() and write() In contrast to a text file which store data as characters (text), a binary file can store the data as binary information, storing data as they are without converting them into text, storing their structure so that the data is integer, array or structure.

Two useful functions can access a binary file, namely write() and read(). A file can be written into by use of the write() function. Similarly, a binary file can be accessed sothat the data can be retrieved by use of read( ) function. Theses two functions require two arguments, the first is the address of the variable, to be written to the file or the address of the variable where the data from file be read from. One additional function is to cast the address of variable to a pointer to character.

The general form of write and read are as follows:

read((char *) &variablename, sizeof(variablename));

write((char *) &variablename, sizeof(variablename));



#include<iostream> #include<fstream> #include<cstdlib> using namespace std; fstream faccess("file.dat",ios::out |ios::in | ios::binary); main(){ int i,x, newx; for(i=1; i<=5; i++) faccess.write(( char *)&i,sizeof(int)); //writing to file faccess.seekg(0,ios::beg); for(i=1; i<=5; i++){ faccess.read(( char *)&x,sizeof(int)); cout<< " X IS "<<x<<endl; }// FOR cout <<" ENTER NUMBER TO REPLACE "<<endl; cin>>x; cout<<" ENTER NEW NUMBER "<<endl; cin>>newx; faccess.seekp((x-1)*sizeof(int)); //First data is from byte zero faccess.write((char *) &newx,sizeof(int)); faccess.seekg(0,ios::beg); for(i=1; i<=5; i++){ faccess.read(( char *)&x,sizeof(int)); cout<< " X IS "<<x<<endl; }// FOR return 0; }//MAIN

Figure 9.13a - Binary file access



X IS 1 X IS 2 X IS 3 X IS 4 X IS 5 ENTER NUMBER TO REPLACE 3 ENTER NEW NUMBER 1000 X IS 1 X IS 2 X IS 1000 X IS 4 X IS 5

Figure 9.13b - Output of Figure 9.13a



BINARY FILE AND STRUCTURE: write( ) and read( ) The following program demonstrates how the write( ) and read( ) functions are used to store and retrieve the data with their structure. The advantage is that, rather than accessing each element of data, the entire structure can be accessed.

#include<iostream> #include<fstream> #include<cstdlib> #include<iomanip> using namespace std; struct person{ char name[20]; char phone[20]; }; person employee; fstream faccess("file.dat",ios::out |ios::in |ios::binary); main(){ int i,n; cout<<"\nInput the name and the phone:\n?"; for(i=1; i<=5; i++){ cin>>employee.name>>employee.phone; faccess.write((char *)(&employee),sizeof(person)); cout<<"\n?"; }// FOR faccess.seekg(0,ios::beg); for(i=1; i<=5; i++){ faccess.read((char *)(&employee),sizeof(person)); cout<<setw(10)<<employee.name<<setw(10)<<employee.phone<<endl; }// FOR cout <<" ENTER EMPLOYEE NUMBER TO REPLACE e.g. 1 to 5: "; cin>>n; cout<<"ENTER EMPLOYEE CHANGED NAME AND PHONE: "; cin>>employee.name>>employee.phone; faccess.seekp((n-1)*sizeof(person)); faccess.write((char *)&employee,sizeof(person)); faccess.seekg(0,ios::beg); for(i=1; i<=5; i++){ faccess.read((char *)&employee,sizeof(person)); cout<<setw(20)<<employee.name<<setw(20)<<employee.phone<<endl; }// FOR return 0; }//MAIN

Figure 9.14a - Binary file with structure





Input the name and the phone: ?Alireza (516)746-8474

?Tara (718)738-7635

?Matthew (212)356-8756

?Sarah (516)784-7864

?Julia (212)839-8767

? Alireza(516)746-8474 Tara(718)738-7635 Matthew(212)356-8756 Sarah(516)784-7864 Julia(212)839-8767 ENTER EMPLOYEE NUMBER TO REPLACE e.g. 1 to 5: 2 ENTER EMPLOYEE CHANGED NAME AND PHONE: Paul (212)738-7873 Alireza (516)746-8474 Paul (212)738-7873 Matthew (212)356-8756 Sarah (516)784-7864 Julia (212)839-8767

Figure 9.14b - Output of Figure 9.14a



RANDOM WRITE TO FILE: write( ) and read( ) The following program illustrates how you can write the data to anywhere in the file and then search for it at a later time. To show the randomness, a random number generator produces a number ranging from 0 to 9999 (e.g. representing last 4 digits of a telephone number). The number is used to seek the file marker and write the name of the person. However the number itself is not stored, but is used as the key. The functions write( ) and read( ) are used as soon as seekp( ) and seekg( ) respectively position the file marker in the proper spot of the file.



#include<ctime> #include<fstream> #include<iomanip> #include <cstdlib> #include<string.h> #include<iostream> using namespace std; fstream faccess("a:data.dat",ios::in|ios::out|ios::binary); main(){ int phone, i; char name[15]; srand(time(0)); for(i=1;i<=5;i++){ phone=rand()%10000; cout<<phone<<endl; cout<<"ENTER A NAME " ; cin>>name; faccess.seekp(phone,ios::beg); faccess.write((char *)&name,sizeof(name)); }// FOR cout<<"ENTER A PHONE "; cin>>phone; char searchname[15]; cout<<"ENTER A SEARCH NAME :"; cin>>searchname; faccess.seekg(phone,ios::beg); faccess.read((char *)&name,sizeof(name)); if (strcmp(searchname,name)==0) cout<<phone<<setw(20)<<name<<endl; else cout<<" NUMBER NOT FOUND "<<endl; return 0; }//MAIN

Figure 9.15b - Out put of Figure 9.15a



TELEPHONE DIRECTORY WITH ARRAY A program and a data file are two separate entities. However, it is necessary for a program to access a file to perform a specific operation. Accessing data from the file each time and storing it in a single designated variable for each performance requires more time than if the data were entirely residing in the program. One way to eliminate accessing the file each time, for every operation to be performed on the file (fill in and refill), is to set aside multiple storage variables (array) in the program and download the entire file to the designated arrays and work on these arrays. With this concept of downloading into an array, all the operations are performed on the array and it is not necessary to access the file anymore, except when the program has to terminate. At the time of program termination, the data from the arrays are copied back to the file for future access.

#include<iostream> #include<fstream> #include<iomanip> #include<string.h> #include<cstdlib> using namespace std; char personname[20][15], phone[20][14]; int myappend(char personname[][15],char phone[][14],int &n){ cout<<"ENTER PERSON NAME "; cin>>personname[n]; cout<<"ENTER THE PHONE "; cin>>phone[n]; n++; return 0; }//MYAPPEND mysearch(char personname[][15], char phone[][14], int n){ char searchname[15]; cout<<"ENTER THE SEARCH NAME "; cin>>searchname; for (int i=0; i<n; i++){ if(strcmp(searchname,personname[i])==0){ cout<<"THE PHONE IS "<<phone[i]<<endl<<endl; return 1; }//IF }// FOR cout<<"NAME NOT FOUND "<<endl<<endl; return 0; }//MYSEARCH mydisplay(char personname[][15], char phone[][14], int n){ for (int i=0; i<n; i++){ cout<<"PERSON NAME IS "<<personname[i]<<endl; cout<<"PHONE IS "<<phone[i]<<endl; }// FOR return 0; }//MYDISPLAY int mymodify(char personname[][15], char phone[][14], int n){ char searchname[15], newphone[14]; cout<<"ENTER THE MODIFY NAME "; cin>>searchname; for (int i=0; i<n; i++){ if(strcmp(searchname,personname[i])==0){ cout<<"ENTER THE NEW PHONE NUMBER"<<endl; cin>>newphone; strcpy(phone[i], newphone); return 1; } }// FOR cout<<"NAME NOT FOUND "<<endl<<endl; return 0; }//MYMODIFY mydelete(char personname[][15], char phone[][14], int n){ char searchname[15]; cout<<"ENTER THE DELETE NAME "; cin>>searchname; for (int i=0; i<n; i++){ if(strcmp(searchname,personname[i])==0){ strcpy(personname[i]," "); strcpy(phone[i]," "); return 1; }//IF }// FOR cout<<"NAME NOT FOUND "<<endl<<endl; return 0; }//MYDELETE int loadintoarray(char personname[][15], char phone[][14], int &n){ ifstream fin("directory.txt"); while(fin>>personname[n]>>phone[n]) n++; fin.close(); return 0; }//LOADINTOARRAY int storetofile(char personname[][15], char phone[][14], int n){ ofstream fout ("directory.txt", ios::out); for (int i=0; i<n; i++){ fout<<setw(20)<<personname[i]<<setw(20)<<phone[i]<<endl; }// FOR return 0; }//STORETOFILE main(){ char option; int n=0; loadintoarray(personname, phone,n); cout<<"SELECT ONE OF THE FOLLOWING "<<endl; while (1){ cout<<"TYPE 1 TO INSERT "<<endl; cout<<"TYPE 2 TO DISPLAY "<<endl; cout<<"TYPE 3 TO SEARCH "<<endl; cout<<"TYPE 4 TO MODIFY"<<endl; cout<<"TYPE 5 TO DELETE "<<endl; cout<<"TYPE # TO QUIT "<<endl<<endl; cin>>option; if (option=='1') myappend(personname, phone, n); else if (option=='2') mydisplay(personname, phone,n); else if (option=='3') mysearch(personname, phone,n); else if (option=='4') mymodify(personname, phone,n); else if (option=='5') mydelete(personname, phone,n); else if (option =='#'){ storetofile(personname, phone, n); cout<<"BYE "<<endl; exit(1); }//IF }//WHILE return 0; }//MAIN

Figure 9.16c -Sample output of the program in Figure 9.16a



FILE WRITING AND READING: THE ENTIRE STRUCTURES It is possible to write the entire data structure to a file in a one shot rather than writing it one item at a time. This is done by the function write () which takes the structure and its size and writes it down to the file. Similarly read () function can read the same structure back by providing the size. This trend can be used with the array of the structures as well.

#include<iostream> #include<fstream> #include<cstdlib> #include<iomanip> #include<string.h> using namespace std; struct person{ char name[20]; long phone; }; person employee[3],testemployee[3]; fstream faccess("file.dat",ios::out |ios::in |ios::binary); main(){ int i; for (i=0;i<3;i++){ cout<<"\nInput the name and the phone:\n?"; cin>>employee[i].name>>employee[i].phone; }// FOR faccess.write((char *)(&employee),sizeof(employee)); faccess.seekg(0); faccess.read((char *)&testemployee,sizeof(testemployee)); for(i=0;i<3;i++) cout<<setw(10)<<testemployee[i].name<<setw(10)<<testemployee[i].phone<<"\n"; return 0; }//MAIN

Figure 9.17a - File read and write



Input the name and the phone: ?Ali 7643

Input the name and the phone: ?Michael 5678

Input the name and the phone: ?Julia 5467 Ali 7643 Michael 5678 Julia 5467

Figure 9.17b -Output of Figure 9.17a



C DIFFERENCES IN FILE HANDLING: ACCESSING INPUT FILE There is not much difference in the syntax of C and C++, but each has its own tradeoff. In C the following steps are needed to use a file:

  1. Declare a file pointer FILE *fp; note that the word FILE is in uppercase.


FILE *fp;



  1. Open the external file with an access mode and assign it to file pointer.
  2. fp=fopen("file.dat","r"); file can be "w" for write, ‘a" for append as well.
  3. Use the file pointer in I/O routine. fscanf(fp,"%d",&x);


FILE *fin;



fin=fopen("file.dat", "r"); fscanf(fin,"%d",x); fstream fin; fin.open ("file.dat", ios::in); fin>>x;

The following are some examples of file handling in C language and its C++ equivalent.

#include<cstdio> using namespace std; main(){ FILE *fpin; int datafield1, datafield2; float datafield3; fpin=fopen ("employee.txt","r"); fscanf(fpin, "%d %d %f",&datafield1,&datafield2,&datafield3); fclose(fpin); }

#include <cstdio> using namespace std; main(){ FILE *fpout; int datafield1,datafield2; float datafield3, datafield4; fpout = fopen("salary.txt","w"); fprintf(fpout,"%4d%2d %7.2f %7.2f\n",datafield1,datafield2,datafield3,datafield4); fclose(fpout); }



Figure 9.18a - Examples of file handling in C



#include<iostream> #include <fstream> using namespace std; main(){ long int id,sid; char name[20]; float price; int counter=0; while (counter<5){ ifstream fin ("super.in"); cout <<" ENTER THE ID "; cin>>sid; while (fin>>id>>name>>price){ if(sid ==id){ cout<<" NAME "<<name<<" PRICE "<<price<<endl; break; }//IF }//WHILE if (fin.eof())cout <<" not found "; counter = counter +1; fin.close(); }//COUNTER LOOP return 0; }//MAIN

Figure 9.18b - File handling in C++ CLOSING REMARKS AND LOOKING AHEAD If it were not for a file, a computer would remain a simple calculator with no backup storage to rely on. Any information stored in a computer is in some form of file. In fact, a keyboard (standard input file), a screen (standard output file), or even a modem is considered a type of file. A program can create, access, or manipulate a file. One kind of file access, where data are accessed one after the other, is known as sequential file access. Alternatively, a file can be accessed here and there randomly at the beginning, at the end or at any spot in the file. This is known as random access. While sequential access is easy and straightforward, it is slow and it does waste memory. On the other hand, random access is faster and does not waste memory; but extra care is necessary to avoid any undesirable effect to the file.

As a file is opened, file indicator (file maker) advances as data is accessed, getting ready for the next operation. A variety of file modes exist, such as ios::in for input and ios::out or ios:app for output. For ios::in and ios::out the file indicator is placed at the beginning. In addition, a restriction can be placed on a file as it is being opened, such as to not create the file, if the file does not exist (ios::nocreate), or to not replace the file if the file already exists (ios::noreplace). Random access can be achieved by using the functions seekp( ) and seekg( ), which position the file indicator at any spot of the file. Therefore, data can be retrieved from or written to the file relative to the current, beginning, or end positions. While by default, files are saved as text files, a file can be created as a binary file, treating the data as it is rather than converting it to a series of text (ASCII) characters. Binary files are better suited for writing and reading data randomly than text files are. With binary files an entire structure was written in one shot by using write( ) function. Similarly, the entire structure was read from the file in the structure by use of read( ) function. One way to apply random access to a file is to fix the size of the data ahead of time. For example, a fixed length must set aside for each record. Using 100 characters (bytes), the 10th record will be placed in the position 1000 to 1099. The use of a key file indicator can speed up random access. However, a wrong key file indicator positioning as a result of bad computation or misplacement may lead to a disaster since the file content will be altered on the spot. There are tradeoffs in all cases.

The content of a file can be dumped into arrays at the beginning and the contents of the arrays stored into the file at the end. Working with arrays is easy and fast. Modification is much easier and deletion can be replaced with a blank or some special value. There may be a problem with too many empty slots in an array when there are several deletions. Also, allocating a huge array in a large database is not logical or, in some cases, there is a limit in the size of the array. The use of linked lists instead of arrays would solve the deletion problem, but it would create its own problem of rapid access. While each of the above files accesses methods and techniques has its own advantages, there are pitfalls in each case. Therefore all tradeoffs are worth learning and analyzing.

SELF-TEST TRUE / FALSE CHAPTER 9: FILE HANDLING __ 1. A file that is used to store or retrieve data is called a data file. __2. In C++, no include directive such as #include <fstream> is needed for file handling. __3. ifstream fin("data.txt", ios::in); associates a file for output access. __4. A file should be closed before it is opened again in another operation mode. __5. A file can be opened for both input and output such as fstream fout("data.dat", ios::in|ios::out); __6. A database has operations such as storing, displaying, and searching for records. __7. A file can be accessed sequentially as well as randomly. __8. The C++ system( ) function enables the programmer to use operating system commands. __9. The most efficient way to delete from a file is to copy the entire file, excluding deleted data. __10. ifstream fin("data.txt",ios::in); if(!fin) cout<<"NO FILE"; will test the file’s existence. __11. ofstream outfile("data.txt", ios::noreplace); prevents an existing file from being overwritten. __12. In a random access file, seekg( ) is used for putting data and seekp( ) is used for getting data. __13. Random access becomes faster if each record has a fixed length with a unique key. __14. Binary files store the binary value of a number instead of its ASCII value. __15. Modification is more difficult in arrays rather than in a sequential file. __16. Using random access, modification can be done by overwriting the record using seekp( ). __17. Using write( ) function from <fstream>, one can write an entire structure (record) to a file. __18. It is better to store large amounts of data into an array rather than into a file. __19. Information in an array will be lost after the program terminates. __20. In sequential files, modification requires duplication of the existing file. __21. In random access there is no need for duplication of the file when deleting a record. __22. When deleting a record from an array the physical storage will be deleted. __23. By using a linked list the deleted record will be physically deleted. __24. It is necessary to shuffle an array upon deletion to make the insertion faster. __25. If the array is not shuffled after deletion, it is necessary to indicate that the record was deleted.

CHAPTER 9 FILE HANDLING ASSIGNMENTS AND CASE STUDY Q9a) Create two files fileA and fileB that contain some data. Write a program to create fileC that will contain the data from fileA and the data from fileB. (fileB is appended to the end)

Q9b) fileA and fileB both contain sorted data; write a program that creates fileC which contains the sorted data from both files.

Q9c) Write a program for a lawyer so that when a clients’ last name is entered, if a file already exists with that name, it will append comments to the end, if it does not exist, it will create a file with that name and allow user to enter comments. You can also save in the file the date when the comment was entered, using system time.

Q9d) Write a supermarket pricing program that will display the item name and price when the barcode (long integer) is entered and determine if it is taxable or not. Create a file containing barcode, item name, item price, and tax status. The program will add all purchased items and display the total price.

Q9e) Most operating system utilities are performed on files. In fact, a directory is a file that contains the names of the files. Write a program to simulate an operating system with the following commands: create, display, copy, delete, compare, and rename. At a later time you may want to use command line arguments, which are explained in chapter twenty.

Q9f) Name one disadvantage of using sequential files; how would you resolve this problem? How is the modification and deletion of a record done?

Q9g) What is one advantage and one disadvantage of using arrays as opposed to files? How is the modification and deletion of a record done?

Q9h) What is the advantage of using random access files? How is the modification and deletion of a record done? Q9i) What are the three major steps in using an input file to access data in a program?

Q9j) What is the output of the following program using an input file? The input file contains the following: 3456123 500.99 #include <fstream> #include <iostream> using namespace std; main(){ long int accountnumber; double balance, amount; ifstream fin ("customer.txt"); fin>>accountnumber>>balance; cout<<" ENTER YOUR WITHDRAW AMOUNT: "; cin>>amount; balance=balance-amount; cout<<"NEW BALANCE IS "<<balance<<endl; fin.close( ); ofstream fout ("customer.txt"); fout <<accountnumber << " " <<balance<<endl; return 0; }//MAIN Q9k) Expand the above program to search for an account number and update the balance after withdrawals and deposits. How do you update the input file so that it can be accessed again?

Q9l) What would go wrong by placing ofstream fout ("customer.txt"); inside a loop?

Q9m) Explain how using system commands such as system (del customer.txt"); and system (rename newcustomer.txt customer.txt"); helps modification and deletion when a sequential file is being used. Hints: The commands rm and mv are Unix equivalents of Microsoft command del and rename.

Q9n) Why is it important to use a statement such as if (!fin) cerr <<"ERROR IN OPENING FILE"; when handling files?

Q9o) What does the following program do?

#include <fstream> #include <iostream> #include <iomanip> using namespace std; int main(){const int RECSIZE=40; int itemid; float price; ofstream fout ("super.txt", ios::out); cout<<"ENTER ITEM ID 0-9999: "; cin>> itemid; fout.seekp(RECSIZE*itemid, ios::beg); cout<<"ENTER NEW PRICE: "; cin>>price; fout<<setw(20)<<itemid<<setw(20)<<price<<endl; return 0; }//MAIN

Q9p) How can a record in the above program be deleted? One strategy for the deletion of an item is to change the price of item to 0. What is the drawback of this method? What is the drawback of your method? Q9q) What does the following program do? What would be the significance of RECSIZE, ios::in, itemid, and seekp? What strategy would you use when inserting the record data (e.g. price) to not have to store the item’s id?

#include <iostream> #include <fstream> #include <iomanip> using namespace std; int main(){const int RECSIZE=40; int itemid; float price; ifstream fin ("super.txt", ios::in); cout<<"ENTER ITEM ID 0-9999: "; cin>> itemid; fin.seekg(RECSIZE*itemid, ios::beg); fin>>itemid>>price; if (price) cout<<"PRICE OF ITEM IS: " <<price<<endl; return 0; }//MAIN

Q9r) It is possible to open a file for both input and output. For example, fsream finout (‘super.txt, ios::in | ios::out); Write a simple program (you may want to combine above programs) to show how this notion and the use of seekp and seekg can be useful to modify a field of a record. Hint: After the desired field is found you must retreat number of bytes. For example seekp(-40,ios::beg).

Q9s) What would be the advantage of using a linked list or a hierarchical structure such as tree to implement your database? What would be the trade-off of these methods versus tables that are represented by arrays or files? How are relational databases different from other databases such as hierarchical or network? Hint: The choice of style and differences among databases is a good research project. However, as a beginner I don’t expect you to know it all but try. You may find the answers in later chapters.

Q9t) What is the difference between a text file and a binary file? How can you view them? In contrast to a text file, which stores data as characters, a binary file can store the data as binary information, storing their structure.

Q9u) Using a binary file with read / write, demonstrate how an entire structure can be manipulated in a simple database. Apply random access with the following: fstream faccess( "data.dat", ios::in | ios::out|ios::binary); faccess.ssekp(empid,ios::beg); faccess.write ((char *) &emprec, sizeof(emprec)); faccess.seekg(empid, ios::beg); faccess.read((char *) &emprec, sizeof(emprec));

Q9v) Convert the following C language file handling to its equivalent in C++. #include <cstdio> using namespace std; main() {FILE *fpout; fpout = fopen ("emp.txt", "a"); fprintf(stdout," ENTER NAME AND SALARY:"); fscanf(srdin, " %s %f",name, &salary);fprintf(fpout,"%s %7.2f \n", name,salary); fclose(fpout); return 0;}

CASE STUDY - PAYROLL SYSTEM PHASE 9: FILE HANDLING

At this phase we are building a simple database with a menu consisting options such as: to insert, to display (page by page), to search, to modify, and to delete. The data for each employee is entered interactively. After the computation of gross pay (regular pay plus overtime pay), tax amount, and net pay, these data are appended to a file. We are going to examine the following ways of file handling to build our sample database.

A) SEQUENTIAL FILE IMPLEMENTATION: In the first part we directly worked with the file in a sequential manner. For each operation on the input data, the file is opened initially and, after the operation is performed, at the end of the function the file is closed. Note that one draw back of sequential file handling is observed when modifying or deleting a record. Modification and deletion of an employee’s record requires copying the file. In the case of large data file it is not efficient to copy the file for each modification and deletion.

B) ARRAY IMPLEMENTATION: The employee data file is copied into arrays upon program execution and, similarly, the arrays are copied to the data file upon the termination of the program. The function n=download( ) will copy the entire file into the appropriate fields (arrays) and return the number of records, which is used by other functions. However, adding an option upload (to save) will copy the arrays to the file. What would be your strategy for deletion of an employee?

C) RANDOM ACCESS: To speed up working with the file is to use random access than sequential access. To do random access you must know the position of each field.

D) CLASS PRIVATE AND PUBLIC: Build an abstract data type (ADT) for the employee class by making this user define type behaving the same way as other system data type. Make your data and auxiliary functions private and make the functions that you need as an interface public. Remember that one goal of ADT is to hide the implementation detail as other system data type implementations are hidden.