0% found this document useful (0 votes)
91 views9 pages

18 - Disk IO

This document discusses input and output (I/O) of files using streams in C++. It introduces the ifstream, ofstream, and fstream classes for input, output, and input/output of files. It provides examples of writing formatted data like integers, doubles, and strings to files using ofstream, and reading the same data back from files using ifstream. It also discusses writing and reading binary data, character I/O, detecting end-of-file, and using getline() to read strings with embedded spaces from files.

Uploaded by

Azhar Jamil
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
91 views9 pages

18 - Disk IO

This document discusses input and output (I/O) of files using streams in C++. It introduces the ifstream, ofstream, and fstream classes for input, output, and input/output of files. It provides examples of writing formatted data like integers, doubles, and strings to files using ofstream, and reading the same data back from files using ifstream. It also discusses writing and reading binary data, character I/O, detecting end-of-file, and using getline() to read strings with embedded spaces from files.

Uploaded by

Azhar Jamil
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 9

AJ/Handout 18 -1- Object-Oriented Programming

Lesson 18
Objectives
 Disk File I/O with Stream
DISK FILE I/O WITH STREAMS
Most of the programs needed to store the data physically on the disk and to read back occasionally.
For this we need another set of classes: ifstream, ofstream & fstream for input, output and
input/output respectively. Their hierarchy is given as:
 ifstream is derived from istream
 fstream is derived from iostream,
 while these base classes further derived from ios
 by multiple inheritance these file-oriented classes also derived from fstreambase class
 fstreambase class has an object of class filebuf, which is a file oriented buffer
 istream, fstream and ostream are declared in FSTREAM header file
Formatted File I/O
In formatted I/O numbers are stored on disk as a series of characters. Thus 6.02, rather than being
stored as 4-byte type float or 8-byte type double, is stored as characters ‘6’, ‘.’, ‘0’, and ‘2’. This
would be inefficient for the numbers but appropriate in many situation and easy implementation.
Writing Data
Following program will write some data of different data types on disk. There is no output to the
screen.
// writes formatted output to a file, using <<
#include <fstream> //for file I/O
#include <iostream>
#include <string>
using namespace std;
int main()
{
char ch = 'x';
int j = 77;
double d = 6.02;
string str1 = "Kafka"; //strings without
string str2 = "Proust"; // embedded spaces

ofstream outfile("fdata.txt"); //create ofstream object

outfile << ch //insert (write) data


<< j
AJ/Handout 18 -2- Object-Oriented Programming

<< ' ' //needs space between numbers


<< d
<< str1
<< ' ' //needs spaces between strings
<< str2;
cout << "File written\n";
return 0;
}
Here we defined an object of fstream named outfile also initialize it with name fdata.txt. This
initialization sets aside many resources and opens the file on the disk. If the file does not exist it is
created. If it exists then old data will be overwritten. oufile object works as cout and << operator
insert the data into new file created; since it is appropriately overloaded in ostream, from which
ofstream is derived. When the program completes file is automatically closed since its destructor is
called automatically. There are some clues to be noted before dealing with files. That is there must
be a space between numbers and other characters since when we read back from file extraction
operator need it. So it means here in files strings can not have embedded blanks.
Reading Data
Similarly the other way round we can use the ifstream object using extraction operator.
// reads formatted output from a file, using >>
#include <fstream> //for file I/O
#include <iostream>
#include <string>
using namespace std;
int main()
{
char ch;
int j;
double d;
string str1;
string str2;
ifstream infile("fdata.txt"); //create ifstream object
//extract (read) data from it
infile >> ch >> j >> d >> str1 >> str2;
cout << ch << endl //display the data
<< j << endl
<< d << endl
<< str1 << endl
<< str2 << endl;
return 0;
}
AJ/Handout 18 -3- Object-Oriented Programming

This program works the same way previous program did but in a reverse manner. Provided that we
have inserted data in correctly we can extract it without any problem. The string characters are
again set to corresponding integers.
Strings with Embedded Blanks
Now problem with previous programs was that we can’t use embedded blanks in strings. We are
already familiar with getline() function so lets see how it would work in this scenario.
// oline.cpp
// file output with strings
#include <fstream> //for file I/O
using namespace std;
int main()
{
ofstream outfile("TEST.TXT"); //create file for output
//send text to file
outfile << "I fear thee, ancient Mariner!\n";
outfile << "I fear thy skinny hand\n";
outfile << "And thou art long, and lank, and brown,\n";
outfile << "As is the ribbed sea sand.\n";
return 0;
}
In this program several lines are written with embedded blanks. Note that these are char strings not
object of string class. Since these are easier to use; hence we use getline function in forth coming
program. Here are its listings:
// file input with strings
#include <fstream> //for file functions
#include <iostream>
using namespace std;
int main()
{
const int MAX = 80; //size of buffer
char buffer[MAX]; //character buffer
ifstream infile("TEST.TXT"); //create file for input
while( !infile.eof() ) //until end-of-file
{
infile.getline(buffer, MAX); //read a line of text
cout << buffer << endl; //display it
}
return 0;
}
But this program is devised for all strings ending with ‘\n’.
AJ/Handout 18 -4- Object-Oriented Programming

Detecting End-of-file
Previously we have read about different flags one of them was eof() flag, which detects end of file.
This is a signal sent to program by operating system when there is no data to read. The return value
is zero for end of file or nonzero, while nonzero value is an address but of no use.
Character I/O
Now we will see the means for character I/O. Here is a program listing that deals with this
scenario.
// file output with characters
#include <fstream> //for file functions
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "Time is a great teacher, but unfortunately "
"it kills all its pupils. Berlioz";
ofstream outfile("TEST.TXT"); //create file for output
for(int j=0; j<str.size(); j++) //for each character,
outfile.put( str[j] ); //write it to file
cout << "File written\n";
return 0;
}
Now we have another program just to get the things back from file.
// file input with characters
#include <fstream> //for file functions
#include <iostream>
using namespace std;
int main()
{
char ch; //character to read
ifstream infile("TEST.TXT"); //create file for input
while( infile ) //read until EOF or error
{
infile.get(ch); //read character
cout << ch; //display it
}
cout << endl;
return 0;
}
AJ/Handout 18 -5- Object-Oriented Programming

Another approach to reading characters from a file is the rdbuf() function, a member of the ios
class. This function returns a pointer to the streambuf (or filebuf) object associated with the stream
object. This object contains a buffer that holds the characters read from the stream, so we can use
the pointer to it as a data object in its own right. As shown in program below:
// file input with characters
#include <fstream> //for file functions
#include <iostream>
using namespace std;
int main()
{
ifstream infile("TEST.TXT"); //create file for input

cout << infile.rdbuf(); //send its buffer to cout


cout << endl;
return 0;
}
Binary I/O
It is recommended to use binary I/O to write numbers on the disk, in which the numbers are store
the way they stored in computer’s RAM memory, rather than as strings of characters. In binary I/O
an integer is stored in 4 bytes, where as in text version any 12345 number can take 5 bytes. Same
is true for float and double. In our coming example we store an array to the disk and then read back
into memory using binary format. For this purpose we use two new functions write() and read() of
ofstream and ifstream respectively. Both of the members think about data in terms of bytes (char
type). They don’t know how the data is being formatted; they simply transfer a buffer full of bytes
from and to a disk file. The arguments of both functions are the addresses of the data buffer and its
length. The address must be cast, using reinterpret_cast, to type char*, and length is the length in
bytes, not number of data items in the buffer. As shown below:
// binary input and output with integers
#include <fstream> //for file streams
#include <iostream>
using namespace std;
const int MAX = 100; //size of buffer
int buff[MAX]; //buffer for integers
int main()
{
for(int j=0; j<MAX; j++) //fill buffer with data
buff[j] = j; //(0, 1, 2, ...)
//create output stream
ofstream os("edata.dat", ios::binary);
AJ/Handout 18 -6- Object-Oriented Programming

//write to it
os.write( reinterpret_cast<char*>(buff), MAX*sizeof(int) );
os.close(); //must close it

for(j=0; j<MAX; j++) //erase buffer


buff[j] = 0;
//create input stream
ifstream is("edata.dat", ios::binary);
//read from it
is.read( reinterpret_cast<char*>(buff), MAX*sizeof(int) );

for(j=0; j<MAX; j++) //check data


if( buff[j] != j )
{ cerr << "Data is incorrect\n"; return 1; }
cout << "Data is correct\n";
return 0;
}
The reinterpret_cast Operator
In above example we have used the reinterpret_cast operator to make it possible for a buffer of
type int to look to the read() and write() function like a buffer of type char.
Object I/O
The most elegant use of streams and files is that to read/write the objects from/to a file. The way to
use this approach is shown here:
// saves person object to disk
#include <fstream> //for file streams
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////
class person //class of persons
{
protected:
char name[80]; //person's name
short age; //person's age
public:
void getData() //get person's data
{
cout << "Enter name: "; cin >> name;
cout << "Enter age: "; cin >> age;
}
};
////////////////////////////////////////////////////////////////
AJ/Handout 18 -7- Object-Oriented Programming

int main()
{
person pers; //create a person
pers.getData(); //get data for person
//create ofstream object
ofstream outfile("PERSON.DAT", ios::binary);
//write to it
outfile.write(reinterpret_cast<char*>(&pers), sizeof(pers));
return 0;
}
Now there is another program to get back the data from the file:
// reads person object from disk
#include <fstream> //for file streams
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////
class person //class of persons
{
protected:
char name[80]; //person's name
short age; //person's age
public:
void showData() //display person's data
{
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
}
};
////////////////////////////////////////////////////////////////
int main()
{
person pers; //create person variable
ifstream infile("PERSON.DAT", ios::binary); //create stream
//read stream
infile.read( reinterpret_cast<char*>(&pers), sizeof(pers) );
pers.showData(); //display person
return 0;
}
Compatible Data Structures
To work correctly with such scenarios it is recommended to use the objects of same class to be
written and read back. The other way round we can’t access (read) the object properly.
AJ/Handout 18 -8- Object-Oriented Programming

However, if we have written object of a class, then we can use it in another class with same
member data but different member functions, since member functions are not written on the disk.
So those don’t play any role if they would differ. This is true for simple classes only.
If we are intended to read and write the objects of derived classes to a file, we need to be careful if
we are using virtual function.
We should also not attempt disk I/O for the objects which contains pointer data members. As we
know that each time address got change we load the program in memory.
I/O with Multiple Objects
We can extend our previous discussion to write more than one objects to memory. As shown in
program below:
// reads and writes several objects to disk
#include <fstream> //for file streams
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////
class person //class of persons
{
protected:
char name[80]; //person's name
int age; //person's age
public:
void getData() //get person's data
{
cout << "\n Enter name: "; cin >> name;
cout << " Enter age: "; cin >> age;
}
void showData() //display person's data
{
cout << "\n Name: " << name;
cout << "\n Age: " << age;
}
};
////////////////////////////////////////////////////////////////
int main()
{
char ch;
person pers; //create person object
fstream file; //create input/output file
//open for append
file.open("GROUP.DAT", ios::app | ios::out |
AJ/Handout 18 -9- Object-Oriented Programming

ios::in | ios::binary );
do //data from user to file
{
cout << "\nEnter person's data:";
pers.getData(); //get one person's data
//write to file
file.write( reinterpret_cast<char*>(&pers), sizeof(pers) );
cout << "Enter another person (y/n)? ";
cin >> ch;
}
while(ch=='y'); //quit on 'n'
file.seekg(0); //reset to start of file
//read first person
file.read( reinterpret_cast<char*>(&pers), sizeof(pers) );
while( !file.eof() ) //quit on EOF
{
cout << "\nPerson:"; //display person
pers.showData(); //read another person
file.read( reinterpret_cast<char*>(&pers), sizeof(pers) );
}
cout << endl;
return 0;
}
The open()&close() member functions
As their names are concerned both are used to open and close file for processing. It is important for
a file to get close for changes to be saved for the next time. And also for being used frequently; an
already open file can not be written so we must use close and open all the time since this is more
appropriate way to handle the files.
The Mode Bits
These are the bits used with some function to specify out the operation being carried out. Like in
open() function we used in/out mode bits to open the file for reading and writing purposes
respectively. And similarly ate mode bit to start reading or writing from/to end of the file. We also
used ios::app in order to preserve the existing data; we simply append the new data to the file.
Also another important aspect in this way, that before reading the file; we need to initialize the
control from start of the file, such that; we could read all the data; it can be achieved by using
seekg(0) function. See table 12.10 for further details.

You might also like