This section shows how the file streams are used to do sequential and random access file I/O
For file I/O you must include the <fstream> library which defines ifstream and ofstream streams that enable character (char) input from, and output to, files.
Files are opened by creating objects of type ifstream or ofstream.
Files must be closed when no longer needed (fstream
destructor will close will).
Writing Strings to a File
The overloaded operator<<()
can be used to write character strings to a file just like it is used to write
character strings to cout
/* This program
demonstrates writing strings to an output file
*/
#include <iostream>
#include <fstream>
using namespace std;
void main(){
//create file stream on output file
char * fileName = "phoneData.txt";
ofstream file(fileName, ios::out); //ios::out
-> output, ios::app -> append (defined in std)
if(!file){
cout << "ERROR: could not open file "
<< fileName << " ...exiting\n";
exit(1);
}
cout << "Please enter names and phone numbers one line at
time, for example\n";
cout << "John Smith 234-7689\n";
cout << "enter <crtl>-z to end\n";
const int MAX_SIZE = 80;
char firstName[MAX_SIZE];
char lastName[MAX_SIZE];
char phoneNumber[MAX_SIZE];
//read data from user via cin and write
it to the text file
while(cin >> firstName >> lastName >> phoneNumber){
file << firstName << " " << lastName
<< " " << phoneNumber << "\n";
}
file.close(); //fstream destructor will
also close the file
}
Reading Strings to a File
The overloaded operator>>()
can be used to read character strings from a file like it is used to write
character strings from cin
/* This program
demonstrate writing strings to an output file
*/
#include <iostream>
#include <fstream>
#include <iomanip> //for setw() stream method
using namespace std;
void main(){
/*
read the contents of a file whose data is expected to be in
the form:
Louis Johnson 534-6578
John West 456-1112
Anne Smith 567-1234
*/
char * fileName = "phoneData.txt";
ifstream file(fileName, ios::in); //ios::in -> input
if(!file){
cout << "ERROR: could not open file "
<< fileName << " ...exiting\n";
exit(1);
}
const int MAX_SIZE = 80;
char firstName[MAX_SIZE];
char lastName[MAX_SIZE];
char phoneNumber[MAX_SIZE];
//read data from user via cin and write
it to cout in columns
//Note std::left means left justify
// std::right means right justify
// std::setw(x) means set witdth of field
cout << "contents of file: " << fileName << "\n";
cout << "=================================\n";
while(file >> firstName >> lastName >> phoneNumber){
cout << left << "read: " << setw(10)
<< firstName << setw(10) << lastName << phoneNumber << "\n";
}
cout << "...closing input file\n";
file.close(); //fstream destructor will also close the file
}
Writing Bytes to a File
The ofstream's write method is used to write bytes to a file.
write(const char * p, int n) will write to the file the n bytes (or chars) that are pointed to by p.
In this example the bytes are used to represent a binary version of an Student object. Notice how the Student class has been designed so that all Student objects occupy the same amount of memory (regardless of length of the student's name).
//file student.h
class Student{
private:
//student memory is designed so that each student objects
occupies
//the same amount of memmory regardless of the length of there first
//and last name
int studentNumber;
char firstName[20];
char lastName[20];
public:
Student(){
studentNumber = -1;
strcpy(firstName, "unknown");
strcpy(lastName,"unknown");
}
Student(const char * fName, const char * lName, int stdNumber){
studentNumber = stdNumber;
strcpy(firstName, fName);
strcpy(lastName,lName);
}
void printOn(ostream & stream) const {
stream << firstName << " " <<
lastName << " #" << studentNumber;
}
int
getStudentNumber(){return studentNumber;}
};
ostream & operator<<(ostream & stream, const Student & s){
s.printOn(stream);
return stream;
}
//file
ex3_fstream_output2.cpp
/* This program demonstrates writing students to a file as
constant size records which will accommodate random access later
*/
#include <iostream>
#include <fstream>
using namespace std;
#include "student.h"
void main(){
//create file stream on output file
char * fileName = "studentData.txt";
ofstream file(fileName, ios::out); //ios::out
-> output, ios::app -> append (defined in std)
if(!file){
cout << "ERROR: could not open file "
<< fileName << " ...exiting\n";
exit(1);
}
cout << "Please enter students firstName, LastName and
student number, for example\n";
cout << "John Smith 100234587\n";
cout << "enter <crtl>-z to end\n";
const int MAX_SIZE = 80;
char firstName[MAX_SIZE];
char lastName[MAX_SIZE];
int studentNumber;
Student students[100];
int numberOfStudents = 0;
//read data from user via cin and write
it to the text file
while(cin >> firstName >> lastName >> studentNumber){
Student student(firstName, lastName,
studentNumber);
students[numberOfStudents++] =
student;
//cast student
object to a bunch of char's (binary image of student)
//and write out that number of bytes
(chars)
file.write( (const char *) &student,
sizeof(student) );
//or better
yet:
//file.write( reinterpret_cast<const
char *>( &student), sizeof(student) );
}
file.close(); //fstream destructor will also close the file
cout << "\nStudents:\n";
cout << "==========\n";
for(int i=0; i<numberOfStudents; i++)
cout << students[i] << "\n";
}
Reading Bytes from a File
The ifstream's read method is used to read bytes to a file.
read(char * p, int n) will read from the file n bytes (or chars) and put them in memory pointed to by p.
In this example the bytes representing a binary version of a Student object's data are read into the memory of a Student object. In this example all Student objects are assumed to occupy the same amount of memory.
/* This program
demonstrates reading in student objects that
have been stored as constant size binary records
*/
#include <iostream>
#include <fstream>
using namespace std;
#include "student.h"
void main(){
/*
read the contents of a file whose data is expected to be
constant
size Student records
*/
char * fileName = "studentData.txt";
ifstream file(fileName, ios::in); //ios::in
-> input
if(!file){
cout << "ERROR: could not open file "
<< fileName << " ...exiting\n";
exit(1);
}
Student student;
cout << "contents of file: " << fileName << "\n";
cout << "=================================\n";
int i=0;
while(file && !file.eof()){
file.read( (char *) &student,
sizeof(student) );
//or better:
//file.read( reinterpret_cast<char
*>( &student), sizeof(student) );
//if statement
is to ensure that last student is not printed twice
if(!file.eof()) cout << student <<
"\n";
}
cout << "...closing input file\n";
file.close(); //fstream destructor will also close the file
}
Writing Random Access Data to a File
A ofstream maintains an offset, or "put-pointer", which indicates where the next byte will be written by the write method.
The ofstream method long tellp() returns the current position of the put pointer.
The ofstream method
seekp(int n) sets the put offset to
n bytes past the start of the stream.
The ofstream method
seekp(int n, ios::beg) set the put offset to n
bytes past the start of the stream.
The ofstream method
seekp(int n, ios::cur) sets the put offset to n
bytes past the current put offset.
The ofstream method
seekp(int n, ios::end) sets the put offset to n
bytes before the end of file.
/* This
program demonstrates writing students to a file as
constant size records in a random access manner
*/
#include <iostream>
#include <fstream>
using namespace std;
#include "student.h"
void main(){
//create file stream on output file
char * fileName = "studentRecords.txt";
ofstream file(fileName, ios::out); //ios::out
-> output, ios::app -> append (defined in std)
if(!file){
cout << "ERROR: could not open file "
<< fileName << " ...exiting\n";
exit(1);
}
int numberOfRecords = 100;
Student student;
//Write a collection of "blank" student
records as place holders in the file
for(int i=0; i<numberOfRecords; i++){
file.write( (const char *) &student,
sizeof(student) );
}
cout << "Please enter index[0..." << numberOfRecords << "],
students firstName, LastName and student number, for example\n";
cout << "10 John Smith 100234587\n";
cout << "enter <crtl>-z to end\n";
const int MAX_SIZE = 80;
int recordIndex;
char firstName[MAX_SIZE];
char lastName[MAX_SIZE];
int studentNumber;
//read data from user via cin and write
it to the text file
while(cin >> recordIndex >> firstName >> lastName >>
studentNumber){
Student aStudent(firstName, lastName,
studentNumber);
if(recordIndex >= 0 && recordIndex <
numberOfRecords){
//position the file put-pointer to the correct record
file.seekp(recordIndex * sizeof(aStudent));
//cast student object to a bunch of char's (binary image of student)
//and write
out that number of bytes (chars)
file.write(
(const char *) &aStudent, sizeof(aStudent) );
//or better yet:
//file.write(
reinterpret_cast<const char *>( &student), sizeof(student) );
}
}
cout << "....closing file " << fileName << "\n";
file.close(); //fstream destructor will
also close the file
}
Reading Random Access Data to a File
A ifstream maintains an offset, or "get-pointer", which indicates where the next byte from which data will be read.
The ifstream method long tellg() returns the current position of the get pointer.
The ofstream method
seekg(int n) sets the get offset to
n bytes past the start of the stream.
The ofstream method
seekg(int n, ios::beg) set the get offset to n
bytes past the start of the stream.
The ofstream method
seekg(int n, ios::cur) sets the get offset to n
bytes past the current put offset.
The ofstream method
seekg(int n, ios::end) sets the get offset to n
bytes before the end of file.
/* This program demonstrates reading in student objects that
have been stored as constant size binary records both sequentially
and in a random access manner
*/
#include <iostream>
#include <fstream>
using namespace std;
#include "student.h"
void main(){
/*
read the contents of a file whose data is expected to be constant
size Student records
*/
char * fileName = "studentRecords.txt";
ifstream file(fileName, ios::in); //ios::in -> input
if(!file){
cout << "ERROR: could not open file " << fileName << " ...exiting\n";
exit(1);
}
Student student;
//read students sequentially and print the ones with
//valid student numbers along with their record location
cout << "contents of file: " << fileName << "\n";
cout << "=================================\n";
int numberOfRecords = 0;
int i=0;
while(file && !file.eof()){
file.read( (char *) &student, sizeof(student) );
//if statement is to ensure that last student is not printed twice
if(!file.eof()) {
numberOfRecords++;
if(student.getStudentNumber() > 0){
cout << "[" << numberOfRecords-1 << "] " << student << "\n";
}
}
}
cout << "records read: " << numberOfRecords << "\n";
cout<< "Please enter record number[0..." << numberOfRecords << "] (crtl-z to quit) ";
int recordIndex;
//read data from user via cin and write it to the text file
while(cin >> recordIndex){
Student aStudent;
if(recordIndex >= 0 && recordIndex < numberOfRecords){
//clear the EOF indicator and position the file get-pointer to the correct record
file.clear();
file.seekg(recordIndex * sizeof(aStudent));
//read the student record
file.read( (char *) &aStudent, sizeof(aStudent) );
cout << aStudent << "\n";
}
cout<< "Please enter record number[0..." << numberOfRecords << "] (crtl-z to quit) ";
}
cout << "...closing input file\n";
file.close(); //fstream destructor will also close the file
}