C++ School Assignment? Project Due Tomorrow? Chat LIVE With A Programming Expert!

Welcome to Dream.In.Code
Become a C++ Expert!

Join 300,494 C++ Programmers for FREE! Get instant access to thousands of C++ experts, tutorials, code snippets, and more! There are 1,861 people online right now. Registration is fast and FREE... Join Now!




Stringstream tutorial

 
Reply to this topicStart new topic

> Stringstream tutorial, Using a stringstream to read input from a csv file

r.stiltskin
Group Icon



post 27 Mar, 2009 - 11:17 PM
Post #1


You can think of a stringstream as a file loaded into something resembling a string, or alternatively, as a sort of string that you can write to and read from like a file. It's not exactly either of those things, but read on and it should become clearer...

A stringstream works essentially the same as an input/output file stream. You need the preprocessor directive #include <sstream>, declare a stringstream just like an fstream, for example
stringstream ss;
and, like an fstream or cout, you can write to it:
ss << myString; or
ss << myCstring; or
ss << myInt;, or float, or double, etc.

and you can read from it:
ss >> myChar; or
ss >> myCstring; or
ss >> myInt; This is also an easy way to convert strings of digits into ints, floats or doubles.

You can get the entire contents of the stringstream as a single C++ string:
string s = ss.str();

And it also inherits many other members from istream and ostream like get, getline, read, write, put, ... In this code I used the stringstream as an intermediate step between an input (text) file and an int array to help deal with the fact that the data within each line of the file was separated by commas, but the lines are separated only by newlines.

Following is a sample program using a stringstream to read numbers from a csv file named "input.txt" into a 6 row by 5 column int array and then prints the array.

It can take data from an input (text) file that looks like this:
CODE
1,3,10,3,1
1,10,10,3,10
1,,,,
0,0,0,1,10
1,1,0,2,2
10,1,0,1,10
and this is what ends up in the array:
CODE
1 3 10 3 1
1 10 10 3 10
1 0 0 0 0
0 0 0 1 10
1 1 0 2 2
10 1 0 1 10


It uses both forms of the istream getline member. Both of them take characters from the stream, copy them into a char array and terminate them with a '\0'.
The first one reads up to n-1 characters or until it reaches a newline or eof:
istream& getline (char* s, streamsize n );
The second one reads up to n-1 characters or until it reaches the character specified as 'delim' or eof:
istream& getline (char* s, streamsize n, char delim );


CODE
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

const int ROWS = 6;
const int COLS = 5;
const int BUFFSIZE = 80;

int main() {
  int array[ROWS][COLS];
  char buff[BUFFSIZE]; // a buffer to temporarily park the data
  ifstream infile("input.txt");
  stringstream ss;
  for( int row = 0; row < ROWS; ++row ) {
    // read a full line of input into the buffer (newline is
    //  automatically discarded)
    infile.getline( buff,  BUFFSIZE );
    // copy the entire line into the stringstream
    ss << buff;
    for( int col = 0; col < COLS; ++col ) {
      // Read from ss back into the buffer.  Here, ',' is
      //  specified as the delimiter so it reads only until
      //  it reaches a comma (which is automatically
      //  discarded) or reaches the 'eof', but of course
      //  this 'eof' is really just the end of a line of the
      //  original input.  The "6" is because I figured
      //  the input numbers would be 5 digits or less.
      ss.getline( buff, 6, ',' );
      // Next, use the stdlib atoi function to convert the
      //  input value that was just read from ss to an int,
      //  and copy it into the array.
      array[row][col] = atoi( buff );
    }
    // This copies an empty string into ss, erasing the
    //  previous contents.
    ss << "";
    // This clears the 'eof' flag.  Otherwise, even after
    //  writing new data to ss we wouldn't be able to
    //  read from it.
    ss.clear();
  }
  // Now print the array to see the result
  for( int row = 0; row < ROWS; ++row ) {
    for( int col = 0; col < COLS; ++col ) {
      cout << array[row][col] << " ";
    }
    cout << endl;
  }
  infile.close();
}


The above code was set up explicitly to load data into a 6x5 array because that's what a particular application required, but it can be easily modified to read an entire input file of indeterminate length using a while loop, i.e.
while( infile.getline( buff, 50 ) ) , containing lines with any number of comma-separated values (as long as a big enough buffer is provided). Here's an example of that (it only prints the first 10 columns of the first 10 rows of the array so as not to fill your screen with 0's:
CODE
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

const int ROWS = 100;
const int COLS = 80;
const int BUFFSIZE = 80;

int main() {
  // The array must be big enough to fit the input data.
  int array[ROWS][COLS] = {0};
  int row, col;
  char buff[BUFFSIZE]; // a buffer to temporarily park the data
  ifstream infile("input.txt");
  stringstream ss;
  // Read input into the buffer a line at a time, until
  //  end of file is reached (newlines are automatically
  //  discarded).  The buffer must be big enough to fit
  //  an entire line from the file.
  // Notice that while reading from the file we check how
  //  many rows have been read, to avoid writing beyond
  //  the end of the array.
  row = 0;
  while( infile.getline( buff,  BUFFSIZE ) && row < ROWS ) {
    // copy the entire buffered line into the stringstream
    ss << buff;
    // Read from ss back into the buffer.  Now, ',' is
    //  specified as the delimiter so it reads only until
    //  it reaches a comma (which is automatically
    //  discarded) or reaches the 'eof', but of course
    //  this 'eof' is really just the end of a line of the
    //  original input.  The "10" means this will handle
    //  input numbers of 9 digits or less.
    //  While reading from the stringstream, we check
    //  how many columns have been read to avoid
    //  writing past the end of the array.
    col = 0;
    while( ss.getline( buff, 10, ',' ) && col < COLS ) {
      // Next, use the stdlib atoi function to convert the
      //  input value that was just read from ss to an int,
      //  and copy it into the array.
      array[row][col] = atoi( buff );
      ++col;
    }
    // This copies an empty string into ss, erasing the
    //  previous contents.
    ss << "";
    // This clears the 'eof' flag.  Otherwise, even after
    //  writing new data to ss we wouldn't be able to
    //  read from it.
    ss.clear();
    ++row;
  }
  // Now print the array to see the result
  for( int _row = 0; _row < 10; ++_row ) {
    for( int _col = 0; _col < 10; ++_col ) {
      cout << array[_row][_col] << " ";
    }
    cout << endl;
  }
  infile.close();
}


This post has been edited by r.stiltskin: 2 Apr, 2009 - 09:42 PM
Go to the top of the page
+Quote Post


Register to Make This Ad Go Away!


Reply to this topicStart new topic
2 User(s) are reading this topic (2 Guests and 0 Anonymous Users)
0 Members:

 


Lo-Fi Version Time is now: 11/8/09 04:43AM

Live C++ Help!

Be Social

Dream.In.Code RSS Feed Dream.In.Code LinkedIn Group Follow Us On Twitter Fan Us On Facebook

C++ Tutorials

Reference Sheets

C++ Snippets

DIC Chatroom

Bye Bye Ads

Monthly Drawing

Thumb Drive

Top Contributors

Top 10 Kudos This Month