Play interactively with C++ - Streams

Streams

A stream is an abstraction for input/output. You can think of it as a source (input) or destination (output) of characters of indefinite length.

How do you write data to a file in C++?

C++ provides a header filed called (file stream) that exports the ifstream and ofstream types, streams that perform file I/O. Input/output stream class to operate on files.

Objects of this class maintain a filebuf object as their internal stream buffer, which performs input/output operations on the file they are associated with (if any).

In [1]:
#include <fstream>  // std::fstream
In [2]:
std::fstream fs;
fs.open ("iofiles/test.txt", std::fstream::in | std::fstream::out | std::fstream::app);

fs << "More lorem ipsum...."; // write to the created file
fs.close();               // Close the stream
In [3]:
!cd iofiles && ls && cat test.txt
test.txt
More lorem ipsum....
In [4]:
fs.open ("iofiles/test.txt", std::fstream::in | std::fstream::out | std::fstream::app); // Re-open the stream 
fs << "Last but not the least lorem ipsum!!";                                           // Write some more to the file
fs.close();                                                                             // Close the stream
In [5]:
!cd iofiles && ls && cat test.txt
test.txt
More lorem ipsum....Last but not the least lorem ipsum!!

Stream Manipulators

What does the setw manipulator do?

setw(n) sets the minimum width of the input for the next stream operation. If the data doesn't meet the minimum field requirement, it is padded with the default fill character until it is proper size.

In [6]:
#include <iostream>
In [7]:
std::cout << "Output: " << 10 << std::endl;
Output: 10
In [8]:
std::cout << "Output: " << std::setw(5) << 10 << std::endl;
Output:    10

What does the boolalpha manipulator do?

boolalpha determines whether or not the stream should output boolean values as 1 and 0 or as "true" and "false". The opposite manipulator is noboolalpha, which reverses this behaviour.

In [9]:
std::cout << true << std::endl;
1
In [10]:
std::cout << std::boolalpha<< true << std::endl;
true

What do hex, dec, oct manipulator do?

They set the radix on the stream to either octal (base 8), decimal (base 10), or hexadecimal (base 16). This can be used either to format output or change the base for input.

In [11]:
std::cout << 10 << std::endl;
10
In [12]:
std::cout << std::dec << 10 << std::endl;
10
In [13]:
std::cout << std::oct << 10 << std::endl;
12
In [14]:
std::cout << std::hex << 10 << std::endl;
a

What is stream failure? How do you check for it?

Because stream operations often involve transforming data from one form into another, stream operations are not always guaranteed to succeed.

Let's use the previously created test.txt file to demonstrate stream failure.

For the following program:

  • If the file test.txt contains NUM_INTS consecutive integer values, then this code will work correctly.
  • If we try to read stream data of one type into a variable of another type, rather than crashing the program or filling the variable with garbage data, the stream fails by entering an error state and the value of the variable will not change. Once the stream is in this error state, any subsequent read or write operations will automatically and silently fail which can be a serious problem .

To check if a stream is in an erroneous state, we use the .fail() member function.

In [15]:
#include <fstream>
In [16]:
fs.open ("iofiles/test.txt", std::fstream::in | std::fstream::out | std::fstream::app);
In [17]:
int NUM_INTS = 5;
In [18]:
for(int i = 0; i < NUM_INTS; i++){
    int value;
    fs >> value;
    /*..... Do something Here ....*/
    if(fs.fail()) break;
    std::cout << value << std::endl;
}

As you can see, when the program realizes that the file contains text and not integers, it breaks out of the loop without doing any subsequent operation.

What is a stringstream?

In C++, you can't add numbers to strings and when you can, it's almost certainly won't do what you expected.

One solution to this problem is to use another kind of stream object known as a stringstream, exported by sstreamheader. Like console streams and file streams, stringstreams are stream objects. Instead of reading or writing data to an external source, stringstreams store data in temporary string buffers.

In [19]:
#include <sstream> // std::stringstream, std::stringbuf
In [20]:
std::stringstream ss;
ss << "Hello World! It's " << 135 << std::endl;

Once you have put data into a stringstream, you can retrieve the string you have created using the .str() member function.

In [21]:
std::string s = ss.str();
std:: cout << s << std::endl;
Hello World! It's 135

stringstreams are an example of an iostream, a stream that can perform both input and output, You can both insert data inot a stringstream to convert the data to string and extract data from a stringstream to convert string data into a different format. For example:

In [22]:
std::stringstream myConverter;
int myInt;
std::string myString;
double myDouble;
In [23]:
std::cout << myInt << std::endl;
std::cout << myString << std::endl;
std::cout << myDouble << std::endl;
0

0
In [24]:
myConverter << "5 World 3.14"; // Insert string data
In [25]:
myConverter >> myInt >> myString >> myDouble; // Extract mixed data
In [26]:
std::cout << myInt << std::endl;
std::cout << myString << std::endl;
std::cout << myDouble << std::endl;
5
World
3.14

Write a function that converts an int into a string

In [27]:
std::string intToStr(int myInt){
    std::stringstream ss;
    ss << myInt;
    std::string s = ss.str();
    return s;
}
In [28]:
std::string str = intToStr(5);
std::cout << str << std::endl;
5

Draw a tringle by drawing a single character on one line, then three on the next, ...

In [29]:
void DrawTriangle(int numRows){
    
    for(int i = 1 ; i <= numRows; i++) {
    //Print a field of spaces equal to the number of rows minus half the width of the triangle, plus 2 spaces
    //between the row number and the triangle,
    std::cout << std::setfill(' ') << std::setw(numRows - i + 2) << " ";
        
    //Print a field of pipes equal to the number of row number*2 then subtract 1 to keep the width odd and centered.
    std::cout << std::setfill('#') << std::setw((i * 2 - 1)) << "#";
    std::cout << std::endl;
    }
    
}
In [30]:
DrawTriangle(5)
      #
     ###
    #####
   #######
  #########
In [31]:
DrawTriangle(8)
         #
        ###
       #####
      #######
     #########
    ###########
   #############
  ###############
In [32]:
DrawTriangle(15);
                #
               ###
              #####
             #######
            #########
           ###########
          #############
         ###############
        #################
       ###################
      #####################
     #######################
    #########################
   ###########################
  #############################

Next Time Sequential Containers

Comments