LET’S LEARN
FILES IN C++
INPUT/OUTPUT OPERATIONS WITH FILES
OPENING A FILE
CLOSING A FILE
FILE INPUT FUNCTIONS
Reading of Character Data, End Of File, Reading of Numeric Data
FILE OUTPUT FUNCTIONS
Writing of Character Data, Writing of Numeric Data
READING & WRITING A SET OF CHARACTERS
read(), write()
Checking STREAM-STATE Flags
bad(), fail(), eof(), good(), clear()
INTERNAL STREAM POINTERS : get, put
MANIPULATION OF INTERNAL STREAM POINTERS
tellg(), tellp(), seekg(), seekp()
READING & WRITING A CLASS OBJECT
read(), write()
TEMPLATES IN C++
Function Templates
Applying Function Templates
A computer file in C++ is a permanent resource for storing information as data units. Once a file is created by a program, it can be accessed by other independent programs for processing and reports generation.
INPUT/OUTPUT OPERATIONS WITH FILES
C++ provides the following classes to perform input and output of characters to/from files:
ofstream : Stream class to write
onto files (output file)
ifstream : Stream class to read
from files (input file)
fstream : Stream class to both read
and write from/to files (file)
These
classes are derived directly or indirectly from the classes istream, and ostream. We have already used objects whose types were these
classes: cin is an object of class istream and cout is an object of
class ostream. Therefore, we have already been using
classes that are related to file streams. And in fact, we can use our file
streams the same way we are already used to use cin and cout, with the only difference that we have to associate
these streams with physical files. Let’s start with an example.
PROGRAM 76
Q. Write a program to write a line of text content into a file named “example.txt” using output-file stream Class with an object named myfile. (You can check the file example.txt after program execution to see if the content is written)
#include <iostream> #include <fstream> using namespace std; main () { ofstream myfile;
myfile.open("example.txt"); myfile <<
"I am studying Files in C++ and writing this to a text file.\n"; myfile.close(); } |
This code creates a file called example.txt in the directory in
which your CPP program is running (in this example its F:\Dev-Cpp\ProgramFiles),
and inserts the line of text within quotes, into the file named example.txt. It is similar to cout, but here, the content is
written into a text file and not onto the monitor.
Let’s look further into the details of using files in C++.
OPENING A FILE
We can
open a file with a stream object using open() and its syntax is:
open (filename,
mode);
Where filename is a
null-terminated character sequence of type const
char * (the same type that string literals have) representing the name of
the file to be opened, and mode is an optional parameter with a
combination of File Mode flags as shown in the chart below.
Eg: myfile.open("example.txt");
ofstream myfile;
myfile.open ("example.bin", ios : out
| ios : app | ios : binary);
If the file mode is not specified along with an open(), the corresponding default mode is set automatically for the classes ofstream, ifstream, and fstream.
Class |
Default Mode Parameter |
ofstream |
ios :: out |
ifstream |
ios :: in |
fstream |
ios :: in | ios :: out |
File streams that are opened in the binary mode, perform input and output operations independent of any format considerations. Example to open a file in binary mode is:
ofstream myfile
(“example.bin”, ios::out | ios::app | ios::binary);
To check if a file stream has successfully opened a file, you can call the fail() with no arguments. This member function returns boolean value TRUE if the file did not open “because the file doesn’t exist”. It returns false if the file exists. Most importantly, if the file did not exist, come out of the program immediately using the exit(0) command as there is no point proceeding with execution of the remaining program lines. Declare the header file stdlib when using exit(). The general format for fail() is:
if ( myfile.fail() )
{
/* do
not proceed as File is non-existent and so did not open */
exit(0);
}
else
{
/*
proceed with the program to read/write
into a file */
}
NOTE: exit(0)
indicates successful program termination and exit(1) indicates
unsuccessful program termination. |
CLOSING A FILE
When we have finished with input / output operations on a file, we will close it so that its resources become available again for other operations. The close() is used to close an opened file. This member function takes no parameters, and flushes the associated buffers to close the file.
Eg: myfile.close();
Once this member function is called, the stream object can be used to open another file, and the file is available again to be opened by other processes. In case that an object is destructed (remember constructor/destructor) while still associated with an open file, the destructor() automatically calls the close().
Text Files
Text file streams are those where we do not
include the ios::binary
flag in their opening mode. These files
are designed to store text and thus
all values that we input or output from/to them can suffer some formatting
transformations, which do not necessarily correspond to their literal binary
value. Data output operations on text files are performed in the same way we
operated with cout.
Q. Write a program to write 2 lines of text matter into a file named “example2.txt” using the output-file stream class with myfile as the object. Use fail() to check if file stream successfully opened the file.
#include
<iostream> #include
<fstream> /* if you are using Turbo C++
add header file <stdlib.h> */ using namespace
std; main () { ofstream myfile
("example2.txt"); if (myfile.fail()) { cout<<"Unable to Open File ...
No such file"; exit(0); } myfile << "This is first
line.\n"; myfile << "This is second
line.\n"; myfile.close(); cout << "File Open is
Successful ..."; } |
OUTPUT
Question: Test Your Understanding
In the main() of above program, if you replace
this line: ofstream myfile
("example2.txt"); with this line: ofstream myfile
(""); Can you guess what would happen?
Answer: The fail() and exit() would work and nothing will be written
into the file example2.txt !!! |
FILE INPUT FUNCTIONS
File input
functions are used to fetch data from a file. Common input functions include:
(i) Reading of Character Data
get() is used to read a character from the file. Data input can
be from a file into a variable or from one file to another file. Syntax of get() is:
file_object_name.get(variable);
(ii) End Of File
eof() checks if End-Of-File
has reached. This function returns a boolean value TRUE
when program control reaches the end of a file.
(iii) Reading of Numeric Data
>> operator is used to read numeric data from the file. Syntax is:
file_object_name >> variable;
PROGRAM 78
Q. Write a
program to read text matter from the file named “example2.txt” using the input-file stream class with an object
named myfile. If the file exists,
write file contents onto the screen until end of file contents.
Note: The file example2.txt was created in the previous program.
#include <iostream> #include <fstream> using namespace std; /* if using turbo C++ include the header file <stdlib.h> */ main () { char ch; ifstream myfile
("example2.txt"); if (myfile.fail()) { cout<<"\nUnable to Open
File ...\n"; exit(0); // goes out of the program if the File doesn't exist } cout<<"\nFile
Open Successful. Contents are: \n"; while (!myfile.eof() ) //
if eof is not reached then proceed… { myfile.get(ch); cout << ch; } myfile.close(); } |
OUTPUT
File output
functions are used to write data into a file. Common output functions include:
(i) Writing of
Character Data
put() is used to write a character into the file. Syntax is:
file_object_name.put(variable);
(ii) Writing of Numeric Data
<< operator is used to write numeric data into the file. Syntax is:
file_object_name
<< variable;
PROGRAM 79
Q. Write a program to create a file (MarkList). Accept the name
and 2 marks of a student. Write them into the file. Then read from the file and
print the details with total marks.
#include
<iostream> #include
<fstream> using
namespace std; main() { /* open file
for output or writing into file */ ofstream OutFile("MarkList"); char name_out[20], name_in[20]; int i, tot, m_out[2], m_in[2]; cout<<
"Enter Name: "; cin>>name_out; OutFile<<name_out; for(i=0;i<2;++i) { cout<< "Enter Mark: ";
cin>> m_out[i]; /* "\t" is used to
separate fields in the file */ OutFile<<"\t"<<m_out[i]; } OutFile.close(); /* open file
for input or reading from file */ ifstream
InFile("MarkList"); cout<<
"\n\nM=A=R=K L=I=S=T\n\n"; while(! InFile.eof()) { InFile>>name_in>>m_in[0]>>m_in[1]; cout<<name_in<<"\t"; cout<<m_in[0]<<"\t"; cout<<m_in[1]<<"\t"; } tot=m_in[0] + m_in[1]; cout<<"\n\nTotal
Marks = "<<tot; InFile.close(); } |
OUTPUT
READING & WRITING A SET OF CHARACTERS
(i) read()
The read function is used to read a set of characters from the file. Syntax is:
file_object_name.read((char*) &variable_name, sizeof(variable_name));
(ii) write()
The write function is used to write a set of characters into the file. Syntax is:
file_object_name.write((char*) &variable_name, sizeof(variable_name));
Checking STREAM-STATE Flags
In C++, the state of a stream can be checked by built-in member functions that return a boolean value (flag). Most common functions that help check the state of C++ stream includes:
bad() : Returns TRUE if a reading or writing
operation fails. For example, in the case that we try to write to a file that
is not open for writing, or if the device where we try to write has no space
left.
fail() : Returns TRUE as in the same cases
of bad(), but also in the case that a format error happens, like when an
alphabetical character is extracted when we are trying to read an integer
number.
eof() :
Returns TRUE
when reading a file has reached the end of file.
good() : It is the most generic state flag. It returns FALSE in the same cases
in which calling any of the previous functions would return TRUE.
We can use clear() to reset the stream-state flags checked by any of these member functions.
INTERNAL STREAM POINTERS : get, put
All i/o stream objects have at least, one internal stream pointer.
(i) get Pointer: The get pointer belongs to ifstream and istream objects. It points to the location from where next element for input operation will be read.
(ii) put Pointer: The put pointer belongs to ofstream and ostream objects. It points to the location to which next element for output operation will be written.
The fstream object inherits ‘get’ and ‘put’ pointers from iostream (iostream is derived from both istream and ostream).
MANIPULATION OF INTERNAL STREAM POINTERS
The internal stream pointers that point to the reading or writing locations within a stream can be manipulated using the following member functions:
1. tellg(), tellp()
The tellg()
gives us current position of the get pointer (input file pointer).
The tellp()
gives us current position of the put pointer (output file pointer).
The tellg and tellp member functions have no parameters and return a value of the DATA TYPE pos_type. (pos_type is an “integer data type” representing the “current position” of the get stream pointer for tellg or the put stream pointer for tellp).
2. seekg(), seekp()
The seekg()
helps to reposition the get pointer (input file pointer) to any
required position.
The seekp() helps to reposition the put pointer (output file pointer) to any required position.
Both these functions are overloaded with "2 different prototypes":
(1) First Prototype for seekg(), seekp()
seekg ( position );
seekp ( position );
Using this prototype, the stream pointer is changed to the absolute position (counting from the beginning of the file). The “data type” for this parameter is same as the one returned by functions tellg and tellp (pos_type, which is an integer value).
(2) Second Prototype for seekg(), seekp()
seekg ( offset, direction );
seekp ( offset, direction );
Using this prototype, the position of ‘get’ or ‘put’ pointer is set to an offset value relative to some specific point determined by the direction. ‘offset’ is of the data-type off_type, which is an integer data type. ‘direction’ is of data-type seekdir, which is an enumerated type (enum) that determines the point from where offset is counted. We can use three directions for the offset values:
DIRECTION / SEEKDIR |
MEANING |
ios :: beg |
beginning of a file |
ios :: end |
end of a file |
Ios :: cur |
current position of a file |
PROGRAM 80
Q. Write a program to find out the size of a file.
Note: I
have used the file example2.txt from our previous programs.
#include
<iostream> #include
<fstream> using namespace
std; main () { long begin, end; ifstream myfile
("example2.txt"); begin = myfile.tellg(); myfile.seekg (0, ios::end); end = myfile.tellg(); myfile.close(); cout << "SIZE of the File is: " << (end -
begin) << " bytes.\n"; } |
OUTPUT
READING & WRITING A CLASS OBJECT
read()
The read function is used to read a class object from the file. Syntax is:
file-object-name. read ((char *) &object-name, sizeof (object-name));
Eg: PhoneDiary.read((char*) &BookEntry, sizeof(BookEntry));
write()
The write
function is used to write a class object into the file. Syntax is:
file-object-name. write
((char *) &object-name, sizeof (object-name));
PROGRAM 81
Q. Write a program using read() and write()
to create Phone Book of customers for a shop. It must store, retrieve and print
name, phone no, and age of one or more people.
#include <iostream>
#include <fstream>
using namespace std;
class TelephoneBook
{
private:
char
name [30];
char
phone[20];
int
age;
public:
void
ReadData();
void
PrintData();
};
void
TelephoneBook :: ReadData()
{
cout<<"Customer
Name : ";
cin.getline(name,
30); // accept name
with space
cout<<"Customer
Ph.No : ";
cin.getline(phone,
20);
cout<<"Customer
Age : ";
cin>>age;
}
void
TelephoneBook :: PrintData()
{
cout<<"\nName:
"<<name;
cout<<"\nPh.
: "<<phone;
cout<<"\nAge
: "<<age;
}
main ( )
{
fstream
PhoneDiary;
TelephoneBook
BookEntry;
char
UserChoice;
UserChoice = 'y';
PhoneDiary.open("PhoneBook",ios::out);
/* open file for read, write */
while (UserChoice == 'y' || UserChoice == 'Y') /* accept, write data to file */
{
BookEntry.ReadData();
PhoneDiary.write((char *) &BookEntry,
sizeof(BookEntry));
cout << "Do you want to enter more
records? [Y/N] : ";
cin >> UserChoice;
cin.ignore(); /* removes unwanted space which auto skips next entry */
}
PhoneDiary.close();
PhoneDiary.open("PhoneBook",ios::in);
/* move get pointer to the start */
PhoneDiary.seekg(0,ios::beg);
cout<<"\nP=H=O=N=E B=O=O=K\n";
while (PhoneDiary.read((char*) &BookEntry,
sizeof(BookEntry))) /* EOF */
{
BookEntry.PrintData();
cout<<"\n-----------------\n";
}
PhoneDiary.close();
}
In C++ the template defines a family of “functions” or "classes” that can operate on different types of information. This allows a function or class to work on many different data types without being rewritten for each one.
Function templates are special functions that can operate with generic types. This allows us to create functionality that can be adapted to more than one type or class without repeating the entire code for each type. In C++ this can be achieved using template parameters.
A template parameter is a special kind of parameter that can be used to pass a type as argument. Just like how regular function parameters can be used to pass values to a function, template parameters allow to also pass types to a function. The function templates can use these parameters as if they were any other regular type. The format for declaring function templates with type parameters is:
template <class typename> return-type
func-name
(parameter list) { // body of function } |
Refer to following program on how to use C++
Templates.
PROGRAM 82
Q. Create a template function that returns the greater of two
objects.
#include <iostream> using namespace std; template <class myType> myType GetMax(myType a, myType b) {return
(a>b?a:b);} main() { cout<<"Greater value is
"<<GetMax(21,22); } |
OUTPUT
Greater value is 22 .
Here we have created a template function
with myType as its template
parameter. This template parameter represents a type that has not yet been
specified, but that can be used in the template function as if it were a
regular type. The function template GetMax
receives 2 parameters a, b of type myType. After processing
the 2 values, GetMax function returns the bigger of two parameters.
When C++ compiler encounters the functional call to template function GetMax, it uses the template to automatically generate a function replacing each appearance of myType by the type passed (for a, b) as the actual template parameter (integer, in this case) and then calls it. This process is automatically performed by the compiler and is invisible to the programmer. Here is another example.
Applying Function Template
PROGRAM 83
Q. Use a Function Template to accept two numbers from keyboard and find biggest among them. Then accept two characters from keyboard and find biggest character using the same Function template.
#include <iostream> using namespace std; template <class T> T GetMax(T a, T b) {T result; result = (a>b) ? a : b; return (result); } main () { int i, j; char ch1, ch2; cout << "Enter 1st
number : "; cin>>i; cout << "Enter 2nd
number : "; cin>>j; cout << "Bigger
number is : "<<GetMax(i, j)<<"\n\n"; cout << "Enter 1st character: "; cin>>ch1; cout << "Enter 2nd
character: "; cin>>ch2; cout << "Bigger character is: "<<GetMax(ch1, ch2); } |
Therefore, result will be an object
of same type as the parameters a and
b when the function template is
instantiated with a specific type. In this specific case where the generic type
T is used as a parameter for GetMax()
the compiler can find out automatically which data type has to instantiate
without having to explicitly specify it. So we have used:
int i, j;
GetMax (i, j);
and then we used,
char ch1, ch2;
GetMax (ch1, ch2);
No comments:
Post a Comment