CSCI1540
Fundamental Computing
with C++
Stream I/O and File I/O
Fall, 2024
Outline
• Basics of Stream I/O
• File I/O vs. Console I/O
• Class ifstream and ofstream
• Formatting output values
• Member functions in istream/ostream and
ifstream/ofstream
• Treating strings as I/O streams
(istringstream/ostringstream) (Optional)
2
Introduction
• What is File I/O?
• What is Stream I/O?
• Stream of bytes → Sequence of bytes
• Data are read from an input stream one character at a
time
• Data are sent to the output stream one character at a
time.
• Why do we need File I/O?
3
Abstraction of I/O (Console I/O)
Bytes or
Stream converted
of bytes cin high-level data
Keyboard (An istream object)
C++
Stream Bytes or high-
Program
of bytes cout level data
Console
(An ostream object)
• istream and ostream objects act as “middle
persons” between C++ programs and the I/O sources
(e.g., keyboard, console screen)
• These objects offer member functions and overloaded
operators for programmers to perform both low-level
(unformatted) and high-level (formatted) I/O 4
Low-Level and High-Level I/O
• Low-level I/O
• Unformatted
• Deals with individual byte
• Suitable for binary files
• E.g., JPEG Image, MP4 Video files, etc.
• High-level I/O
• Formatted
• Deals with built-in types and user-defined types
• Suitable for plain-text files (files containing only
printable ASCII characters)
5
Abstraction of I/O (File I/O)
Bytes or
Stream converted
Disk
of bytes An ifstream high-level data
input.txt
object
C++
Stream Bytes or high-
Program
of bytes An ofstream level data
output.txt
object
• To perform file I/O, we use ifstream and ofstream
objects
• ifstream and ofstream are subclasses of istream
and ostream respectively
• They offer everything istream/ostream offer plus some
file-specific member functions
6
Steps for Performing File I/O
1. Prepare a stream for reading/writing by creating
an ifstream/ofstream object
2. Read/write data via the stream object
3. When done with File I/O, close the stream
• Release all the resources in the memory associated with
the file
• Flush all data in the memory to the output file if
necessary
• Step 2 is the same as performing I/O using cin and
cout
7
File I/O vs Console (Keyboard) I/O
File I/O Console (Keyboard) I/O
Include both <iostream> Include only <iostream>
and <fstream>
ifstream/ofstream cin/cout are automatically
objects have to be explicitly made available
created. One object per file
File may not be opened Always available
successfully
Need to check when end-of- Usually don't have to check
file is reached (Input only) when end-of-input is reached
Need to close files when done No need to close
using them 8
Filenames and Directory
Structures
• Relative filename
• Relative to the directory (folder) where you run the program
• file1.txt Local Disk (C:)
• ..\Folder B\file2.txt Folder_A
(Windows
• Absolute filename systems) Folder_B
file1.txt
• Full path (up to the root) + filename file2.txt
• C:\Folder C\file1.txt Folder_C
• C:\Folder B\file2.txt file1.txt
program.exe
• Remember to represent \ as \\ in C++ source program
• E.g.: "C:\\Folder C\\file1.txt"
• On some OS (e.g., macOS, Linux), paths are separated
by (/) instead of (\) 9
Preparing a Stream for Reading
• Create objects of the class ifstream for file input
• E.g.:
ifstream fin("input.txt");
Call constructor
Stream type Name of object A c-string or
(variable) string object
(since C++11)
as argument
10
Preparing a Stream for Writing
• Create objects of the class ofstream for file
output
• E.g.:
ofstream fout("output.txt");
• If the file already exists, its original contents will be
erased!
• To retain the original file contents, use:
ofstream fout("output.txt", ios::app);
For “appending”
11
File Output: Example
1 #include <iostream> For using ofstream Content in the
2 #include <fstream> file output.txt
3 using namespace std;
4 Hello!
5 int main() { 0 1 2 3 4 5 6 7 8 9
6 /* Create an ofstream object for output.
7 A file named "output.txt" will be created */
8 ofstream fout("output.txt");
9 1. Create an
10 fout << "Hello!" << endl; ofstream object
11
12 for (int i = 0; i < 10; i++)
2. Write data
13 fout << i << ' ';
14 fout << endl; to stream
15
16 /* Close the stream to indicate that we are done
17 writing data to the file */
18 fout.close(); 3. Close stream
19 return 0;
20 } 12
File Open and Checking
1 #include <iostream>
2 #include <fstream>
3 #include <cstdlib> For using exit()
4 using namespace std;
5
6 int main() {
7 ofstream fout("output.txt");
8
9 // If we fail to open the file for output
10 if ( fout.fail() ) {
11 cout << "Cannot open the file" << endl;
12 exit( 1 ); // Terminate the program
13 }
14 The argument passed to exit()
15 fout << "Hello World\n"; is usually not used. Typically, we
16 fout.close(); use non-zero value to indicate
17 return 0;
18 }
unsuccessful termination
Check if a file is opened successfully before using it 13
File Open and Checking
1 ofstream fout;
2 string filename; We can delay opening a file by
3 using the member function
4 cout << "Enter a filename: "; open(), which expects a file
5 cin >> filename; name as a c-string
6
7 fout.open( filename.c_str() );
8
9 // If we fail to open the file for output
10 if ( fout.fail() ) {
11 cout << "Cannot open the file for output." << endl;
12 exit( 1 );
13 } c_str() is a member
14 function of the string class
15 // Write this to file
16 fout << "Hello World\n";
that returns an equivalent c-
17 string of a string object
18 fout.close(); 14
File Open and Close
1 ofstream fout;
2
3 fout.open("file1.txt"); Stream open and stream
4 … close work in pairs
5 fout.close();
6 …
7
8 fout.open("file2.txt");
9 …
10 fout.close();
11 …
12
13 fout.open("file3.txt");
14 …
15 fout.close(); An ifstream/ofstream object can be reused
to connect to different files, but it can connect
to at most ONE file only at any given time 15
File Reading (Input): Example
1 ifstream fin("data.txt");
2
3 // Terminate if the file cannot be opened for reading
4 if ( fin.fail() ) {
5 cout << "File could not be opened" << endl;
6 exit( 1 );
7 } Content in the
8
9 int x, sum = 0; file data.txt
10 1 27
11 // Assume there is no input error. 3
12 // Read until end of the file is reached
13 while ( !fin.eof() ) { 4
14 fin >> x; 5
15
16 // If successfully read an integer
17 if ( fin.good() )
18 sum += x;
19 }
20 cout << "Sum is " << sum << endl;
21 fin.close(); Sum is 40 16
• ↑ represents the “current file position”. An
ifstream object uses it to remember where (in a
file) to read the next input
1 2 7 \n 3 \n \n 4 \n 5 \n \n
↑
• When a file is opened, the current file position is at
the beginning
• Every character fin reads would advance the
position by one
1 2 7 \n 3 \n \n 4 \n 5 \n \n
↑
• The first time fin >> x is executed, fin reads 1
and stops reading when it encounters a character
that is not part of an integer. The current file
position stays at the unconsumed space character ˽ 17
1 2 7 \n 3 \n \n 4 \n 5 \n \n
↑
• The next time fin >> x is executed, fin will
attempt to read an integer (a sequence of
characters that represents an integer)
1 2 7 \n 3 \n \n 4 \n 5 \n \n
↑
• When fin encounters a character that is not part
of an integer, it stops
• This time, fin reads two bytes and then converts
“27” to integer value 27 and store the value in x
18
1 2 7 \n 3 \n \n 4 \n 5 \n \n
↑
• After fin reads the last integer (the 5th time), the
current file position points at the ‘\n’ after ‘5’
• At this point, fin.eof() is still false
1 2 7 \n 3 \n \n 4 \n 5 \n \n
↑
• When the next fin >> x is executed, fin skips all
whitespace characters until the end of file but it
fails to read any integer
• Thus, fin.good() is false and fin.eof()
becomes true
19
States of a Stream Object
• eof()
• Returns true if file reading has reached the end
• bad()
• Returns true if a reading or writing operation fails due
to some unrecoverable errors
• E.g.: disk full or file is deleted while an I/O operation is taking
place
• fail()
• Returns true if bad() is true or if the previous I/O
operation fails to read/write an expected character
• E.g.: A letter ‘Z’ is encountered when we are trying to read an
integer
• Usually recoverable
• good()
• Returns true if all of eof(), fail(), and bad()
return false 20
Simple Input Error Handling: Example
1 int x;
2 ifstream fin("data.txt");
3 // Suppose the file is opened successfully
4
5 // Read until end of file is reached
6 while ( !fin.eof() ) { Content in the
7 fin >> x; file data.txt
8
9 // If successfully read an integer 1 2A
10 if ( fin.good() ) 3
11 cout << x << endl;
12
13 if ( fin.fail() && !fin.eof() ) {
14 cout << "Failed to read an input value.\n";
15 break; // Stop reading immediately
16 }
17 } 1
18 … 2
19 fin.close(); Failed to read an input value. 21
(Optional)
Checking and Handling “Fail” or
“Bad” States
• For every input operation performed, you should
check if it is successful
• When a stream object state is “fail” or “bad”,
subsequent input operations will not take place
until the state is restored to “good”
• You can use member function clear() to restore the
stream state to “good”, or
• You can just print an error message and stop reading the
input
22
(Optional)
Error Recovery with clear():
Example 1 2 3↵
Valid #: 1
>> returns a non-zero Valid #: 2
1 int x = -1;
2 string tmp;
value if extraction is Valid #: 3
3 successful 123abc↵
4 while (x != 0) { Valid #: 123
5 // If successfully read an integer Invalid #: abc
6 if ( cin >> x ) a 123↵
7 cout << "Valid #: " << x << endl; Invalid #: a 123
8 123 a 456↵
9 if ( ! cin.good() ) { Valid #: 123
10 cin.clear(); Invalid #: a 456
11 // Clear the whole line 0↵
12 getline(cin, tmp); Valid #: 0
13 cout << "Invalid #: " << tmp << endl;
14 }
15 }
23
More about File I/O
• C++ imposes no structure on file
• i.e., no predefined format
• Byte is the basic unit
• To read data from a file, you need to know how the
data are formatted in the file
Program A for writing: Program B for reading:
1 ofstream fout("data.txt"); 1 ifstream fin("data.txt");
2 int i; double d; 2 int i; double d;
3 char c; string s; 3 char c; string s;
4 … 4 …
5 fout << i << endl; 5 fin >> i;
6 fout << d << endl; 6 fin >> d;
7 fout << c << endl; 7 fin >> c;
8 fout << s << endl; 8 fin >> s;
9 fout.close(); 9 fin.close(); 24
ifstream: a Subclass of istream
ofstream: a Subclass of ostream
• ifstream is a subclass of istream
• i.e., an ifstream object can be used as an istream
object
• ofstream is a subclass of ostream
• ifstream and ofstream offer everything
(member functions, etc.) istream/ostream offer
plus some file-specific member functions
25
Example
1 #include <iostream>
2 #include <fstream>
3 using namespace std;
ofstream is a subclass of ostream
4
5 void drawBox(ostream &out) { • Both cout (an ostream object)
6 out << "+-+\n"; and fout (an ofstream object)
7 out << "| |\n"; can be passed to the parameter of
8 out << "+-+\n"; drawBox(…)
9 } • That is, a subclass argument can be
10 passed to a superclass parameter
11 int main() {
12 ofstream fout("output.txt");
13
14 // Suppose the file is opened successfully
15 drawBox(cout); // Output a box on console screen
16 drawBox(fout); // Output a box to "output.txt"
17
18 fout.close();
19 return 0;
20 } 26
Example
1 #include <iostream> • An ifstream/ofstream object
2 #include <fstream> should always be passed as
3 using namespace std; reference parameters, so that I/O
4 can continue in the function
5 void drawBox(ostream &out) { through the same stream object
6 out << "+-+\n"; • If you pass by value, then there will
7 out << "| |\n"; be two stream objects handling the
8 out << "+-+\n"; same file. This is dangerous and can
9 } easily introduce errors
10
11 int main() {
12 ofstream fout("output.txt");
13
14 // Suppose the file is opened successfully
15 drawBox(cout); // Output a box on console screen
16 drawBox(fout); // Output a box to "output.txt"
17
18 fout.close();
19 return 0;
20 } 27
Function in <string> for String
Input
istream& getline( istream &is, string &s);
• Reads characters from is into s until:
• The newline character '\n' is encountered, or
• EOF is encountered
• The delimiter '\n' is removed from the stream but not
included in s
1 // A string object for storing a line of file contents
2 string buf;
3 ifstream fin( "temp.txt" );
4
5 while ( getline( fin, buf ) ) {
6 cout << buf << endl; Example: display the contents
7 } of file “temp.txt”, line by line,
8 fin.close(); using string object 28
(Optional)
Other Member Functions in
istream Object for Input
istream& getline( char* buf, size_t n );
• Reads characters into buf until:
• n - 1 characters have been read, or
• The '\n' delimiter is encountered , or
• EOF is encountered
• Note:
• buf is an array of characters (c-string)
• Delimiter '\n' is consumed but not included in buf
• NULL character '\0' is automatically appended to buf
• The getline() in this page is a member function of istream
class for c-strings
• The getline() in the last page is a function for string objects 29
Low Level I/O
• Sometimes, you may want to perform I/O at a
character level
• Read/writes are performed byte by byte
• E.g., encryption/decryption of a file
• The ostream and istream classes provide several
member functions for such purpose
• ostream::put() for output
• istream::get() for input
30
Member Functions in ostream
for Low-level Output
ostream& put( char ch );
• Writes the character ch to the output stream
• E.g.:
1 // Print A to screen
2 cout.put('A');
3 // Print B and C and \n to screen
4 cout.put('B').put('C').put('\n');
5
6 ofstream fout("output.txt"); // Assume success
7 // Write D to file "output.txt"
8 fout.put('D');
9 // Write E and F and \n to file "output.txt"
10 fout.put('E').put('F').put('\n');
11
12 fout.close(); 31
Member Functions in istream
for Low-level Input
int get();
• Reads a character and returns its ASCII value
• Returns –1 if good() is false
1 int c;
2 ifstream fin( "input.txt" );
3
4 c = fin.get();
5 while (c != -1) {
6 cout.put( (char)c );
7 c = fin.get();
8 }
9 fin.close();
Example: Prints the contents of file “output.txt”, character by character
32
get() vs >>
• get()
• A member function that reads only characters. Won’t
skip whitespaces. Every character counts
• >>
• An operator that reads values of several data types.
Whitespaces may be skipped
• Compare these two code fragments:
1 char ch; 1 ifstream fin("input.txt");
2 ifstream fin("input.txt"); 2 int ch = fin.get();
3 while ( fin >> ch ) 3 while (ch != -1) {
4 cout.put( ch ); 4 cout.put( (char)ch );
5 fin.close(); 5 ch = fin.get();
6 }
7 fin.close(); 33
1 #include <iostream>
2 #include <fstream>
3 #include <string>
4 using namespace std;
5
6 int main() {
7 string input, output;
8 int ch;
9
10 cout << "Enter input file name: ";
11 cin >> input;
12 cout << "Enter output file name: ";
13 cin >> output;
14 ifstream fin( input.c_str() );
15 ofstream fout( output.c_str() );
16
17 while ( (ch = fin.get()) != -1 )
18 fout.put( ch );
19
20 fin.close();
21 fout.close();
22 return 0;
23 }
Example: File Copy (Duplicate)
34
Summary
• 3 steps for performing file I/O:
• Create an ifstream/ofstream object and open a file
• Perform I/O through the stream object
• Close the stream object when done
• How to check if files are opened successfully
• How to check the stream states after every input
operation
Reference:
istream: https://cplusplus.com/reference/istream/istream/
ostream: https://cplusplus.com/reference/ostream/ostream/
ifstream: https://cplusplus.com/reference/fstream/ifstream/
ofstream: https://cplusplus.com/reference/fstream/ofstream/ 35
(Optional)
ostringstream and
istringstream
• The <sstream> library provides these two classes
for manipulating strings as if they are i/o streams
• ostringstream
• Format your data to a string object as output
• Subclass of ostream
string ostringstream
object object
• istringstream
C++
• Read formatted data from a string object as input Program
source
string istringstream
• Subclass of istream object object
36
(Optional)
ostringstream: Example
1 #include <iostream>
2 #include <string>
3 #include <sstream> For using ostringstream
4 using namespace std; and istringstream
5
6 int main() {
7 ostringstream sout;
8 int x = -12;
9 double y = 345.67;
10
11 sout << x << " " << y << endl;
12 sout << "ABC" << endl;
13
14 string s = sout.str();
15
16 cout << "Length = " << s.length() << endl;
17 cout << s; Length = 15
18 return 0; -12 345.67
19 } ABC 37
(Optional)
istringstream: Example
1 #include <iostream>
2 #include <string>
3 #include <sstream>
4 using namespace std;
5
6 int main() {
7 string input_str(" 123 456 78 9012 ");
8 istringstream sin(input_str);
9 int x;
10 while ( !sin.eof() ) {
11 sin >> x;
12 if (sin.good())
13 cout << x * 2 << endl; 246
14 } 912
15 return 0; 156
16 } 18024 38