Streams
Streams
Introduction
In C++, streams are the primary way to handle input and output.
- A stream is simply a sequence of bytes.
- Input/output streams are all sequences of bytes.
- Stream data is read/written byte by byte
- The data is stored in a “buffer” until program needs it.
Input stream
Buffering of input stream:
- All input is stored in the buffer until std::cin extracts it.
- Whitespace characters (like spaces, tabs, and newlines) are usually treated as separators between input values for certain data types.
- The extraction
>>
operator skips leading whitespace automatically (like spaces and newlines) to find the next meaningful input. - <Enter> triggers the processing of input data, sending them to the buffer.
Input data is stored in a buffer until the program requires information from the buffer.
int main() {
int a;
int b;
<< "Enter a: ";
cout >> a;
cin << "Enter b: ";
cout >> b;
cin << "a + b = " << a + b << endl;
cout return 0;
}
- In scenario 2, both inputs are given at once.
- After processing 5, 4 is remained in the buffer and is immediately available for the next input.
- Scenario 1: <Enter> is pressed after each input.
Enter a: 10
Enter b: 20
a + b = 30
- Scenario 2: <Enter> is pressed after the first input.
Enter a: 10 20
Enter b: a + b = 30
Stram states
A stream’s state indicates whether the stream is in a valid state or not.
- Each stream type exposes the constant static members referred to collectively as its bits, which indicate a possible stream state.
Method | State | Meaning |
---|---|---|
cin.good() |
goodbit | The last input operation was successful |
cin.fail() |
failbit | The last input operation failed |
cin.eof() |
eofbit | The end of the file is reached |
cin.bad() |
badbit | The stream has encountered a fatal error |
- To reset the stream state, use
cin.clear()
. - Only
goodbit
is set totrue
.
Recall that every expression has a value and a type, streams implement an implicit bool coonversion, so you can check whether a stream is in a good working state simply.
int main() {
std::string word;
size_t count = 0;
while (cin >> word) {
++count;
}
<< "You entered " << count << " words." << endl;
cout return 0;
}
After compiling your program, try to enter a large paragraph, use <Ctrl-D>
to end the input(Unix) or <Ctrl-Z>
followed by <Enter>
to end the input(Windows).
Handle bad states
When a stream is in a bad state, it remains in that state until the program clears it.
while (!(cin >> number)) {
.clear();
cin.ignore(200, '\n'); // 200 is large enough to ignore any input
cin
<< "Invalid input. Please try again." << endl;
cout }
<< "The number is " << number << endl; cout
cin.clear()
resets the stream state togoodbit
.cin.ignore(200, '\n')
ignores up to 200 characters or until a newline character is encountered. 1
File streams
Introduction
The file stream classes are defined in <fstream>
header, providing facilities to perform input and output operations on files.
ifstream
for input operations,ofstream
for output operations, andfstream
for both input and output operations.- The file stream classes are RAII classes, which means they manage resources automatically. (Just as
unique_ptr
manages dynamic memory.)
Open files
There are two options to open a file:
- Use constructor of the file stream class.
- Use member function
open()
of the file stream class.
#include <fstream>
int main() {
std::ifstream file1("infile.txt");
std::ofstream file2("outfile.txt");
std::fstream file3;
.open("io.txt");
file3
// no need to close the file stream explicitly,
// as the destructor of the file stream class will close the file automatically.
}
Flags
The following table lists the flags used in the file stream classes.
Flag (in std::ios) | File | Meaning |
---|---|---|
in | Must exist | Read |
out | Created if doesn’t exist | Erase the file; then write |
app | Created if doesn’t exist | Append |
in | out | Must exist | Read and write from beginning |
in | app | Created if doesn’t exist | Update at end |
out | app | Created if doesn’t exist | Append |
out | trunc | Created if doesn’t exist | Erase the file; then read and write |
in | out | app | Created if doesn’t exist | Update at end |
in | out | trunc | Created if doesn’t exist | Erase the file; then read and write |
- By default,
ifstream
is inin
mode,ofstream
is inout
mode, andfstream
is inin | out
mode.
Now suppose I have a file named story.txt
in the current directory, and I want to read from it and write to another file named outfile.txt
.
story.txt
must exist. (in
flag)outfile.txt
will be created if it doesn’t exist, if it exists, its content will be erased. (out
flag)
int main() {
// error handling omitted for brevity
std::ifstream inputFile("novel.txt", std::ios::in);
std::ofstream outputFile("outfile.txt", std::ios::out | std::ios::trunc);
std::string word;
while (inputFile >> word) {
<< word << ' ';
outputFile }
std::cout << "Content copied from novel.txt to outfile.txt successfully." << std::endl;
return 0;
}
Error handling in file streams
Similar to input/output streams, file streams also have the four states: goodbit
, failbit
, eofbit
, and badbit
.
The error handling mechanism is similar to that of input/output streams. Here are two ways to check if a file was opened successfully:
- When using a constructor to open a file, you can check using the
is_open()
member function which returns true if the file was opened successfully - When using either the constructor or
open()
method, you can use the implicit bool conversion of the file stream object (which returns false if any error bits are set) - Use
clear()
to reset the stream state togoodbit
.
Example 1
Content of my input file:
This is for a:
51
and now
for b: 100
Task: read the value of a
and b
from the file and save their sum to a new file named result.txt
.
fail()
check: give a number toa
, but read a character/word.- Clear the stream state and ignore the bad input.
eof()
check: keep reading the file until the end.- Exit the loop when reaching the end of the file.
Assignment
You are given a file named hidden_numbers.txt
, which contains characters and numbers, seperated by spaces.
Task: read the numbers from the file and save their sum to a new file named sum_numbers.txt
.
Submission: You only need to write main.cpp
and CMakeLists.txt
, zip them along with hidden_numbers.txt
and submit to Canvas.
std::getline()
std::getline(input_stream, str, delimiter);
- Read a line from the input stream into
str
, stopping beforedelimiter
. - If the delimiter is not found, the function reads the entire remaining content of the stream.
- The default delimiter is
'\n'
. getline()
won’t ignore the whitespace characters.
// print the content of the file line by line
std::ifstream inputFile("story.txt");
std::string line;
while (std::getline(inputFile, line)) {
std::cout << line << std::endl;
}
std::stringstream
The std::stringstream class is part of the <sstream>
header.
- It allows you to treat a string as a stream, enabling you to perform input and output operations on the string.
- It is useful for parsing strings, extracting values, and performing various string manipulations.
Types of stringstream:
std::stringstream
: for both input and output.std::istringstream
: for input only.std::ostringstream
: for output only.
Write and read from a stringstream:
<<
operator is used to write data to the stringstream.>>
operator is used to read data from the stringstream.str()
method is used to get the content of the stringstream as a string.str(<string>)
will set the stream’s content to be<string>
.clear()
method is used to reset the state of the stringstream.
Extract numbers from a string and vice versa
std::stringstream ss;
<< "Age: " << 25 << " Height: " << 5.9; // write to the stringstream
ss
std::string result = ss.str(); // get the content of the stringstream as a string
std::cout << "Formatted string: " << result << std::endl;
std::string label;
int age;
float height;
// suppose we want to use another stringstream to extract the values
std::stringstream ss2;
.str(result); // set the content to the string
ss2.clear(); // optional:reset the stream state to goodbit
ss2
>> label >> age >> label >> height;
ss2
std::cout << "Extracted age: " << age << std::endl;
std::cout << "Extracted height: " << height << std::endl;
Example 2
Content of the input file: A short story.
Task: read the story and count the number of words in it, then save the number to a new file named word_count.txt
.
- Use
getline()
to read the whole file. 2 - Use
stringstream
to split the string into words. - Use
ofstream
to write the result to the file.
Example 3
Given a stock price csv file with the following format:
Date,Open,High,Low,Close,Volume
2024-01-01,100.0,105.0,99.5,102.5,5000
2024-01-02,102.5,108.0,101.0,106.0,6000
2024-01-03,106.0,110.0,105.0,109.5,7000
Task: add a new column named return
to the file, which is the percentage change of the Close
price from the previous day.