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;
cout << "Enter a: ";
cin >> a;
cout << "Enter b: ";
cin >> b;
cout << "a + b = " << a + b << endl;
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 = 30Stram 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
goodbitis 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;
}
cout << "You entered " << count << " words." << endl;
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)) {
cin.clear();
cin.ignore(200, '\n'); // 200 is large enough to ignore any input
cout << "Invalid input. Please try again." << endl;
}
cout << "The number is " << number << endl;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.
ifstreamfor input operations,ofstreamfor output operations, andfstreamfor both input and output operations.- The file stream classes are RAII classes, which means they manage resources automatically. (Just as
unique_ptrmanages 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;
file3.open("io.txt");
// 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,
ifstreamis ininmode,ofstreamis inoutmode, andfstreamis inin | outmode.
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.txtmust exist. (inflag)outfile.txtwill be created if it doesn’t exist, if it exists, its content will be erased. (outflag)
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) {
outputFile << word << ' ';
}
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:
100Task: 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;
ss << "Age: " << 25 << " Height: " << 5.9; // write to the stringstream
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;
ss2.str(result); // set the content to the string
ss2.clear(); // optional:reset the stream state to goodbit
ss2 >> label >> age >> label >> height;
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
stringstreamto split the string into words. - Use
ofstreamto 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.