1

I am overloading my istream operator, so I can replace std::cin with my object. I know I will have to feed it an empty stringstream for the final output to work.

I would like to feed an std::ifstream into a std::stringstream as so:

while(ifs >> ss) {}

Is this possible? Here is an example prototype code:

friend istream & operator >> (istream & is, Database & db)
{
    ifstream ifs;
    ifs.open(db.inputFilename_, ios::in | ios::binary);
    if (!ifs.is_open())
    {
        cout << "Couldn't read " << db.inputFilename_ << endl;
        return is;
    }
    while (ifs >> db.iss)
    {}
    ifs.close()
    return db.iss;
}

I am not interested in any answers that start with "use Boost" :) This is a purely standard C++ project. Thank you for any help or pointers.

Right now I am getting:

error: invalid operands to binary expression ('ifstream' (aka 'basic_ifstream<char>') and 'istringstream' (aka 'basic_istringstream<char>'))
b4hand
  • 9,550
  • 4
  • 44
  • 49
scx
  • 3,221
  • 1
  • 19
  • 37

2 Answers2

3

Simply do this:

 if(ifs){
     db.iss << ifs.rdbuf();    
     ifs.close();
 }
NaCl
  • 2,683
  • 2
  • 23
  • 37
  • 1
    How will this fare with a huge input file? – scx Dec 13 '14 at 21:57
  • Your new example doesn't work with an istringstream, but works with a normal stringstream. I am testing it out right now. BTW thank you! – scx Dec 13 '14 at 22:03
  • Oh yeah, sorry for that. Just use this, its slighty faster than `std::copy`. – NaCl Dec 13 '14 at 22:09
  • This works perfectly, and is *really* fast! Thank you again for your time, it is very much appreciated. – scx Dec 13 '14 at 22:12
  • Faster things are not platform independent and I guess you want that. However this stays as elegant as possible with respect to the speed. – NaCl Dec 13 '14 at 22:17
  • 1
    I always do: c++ standard(platform independant) > elegance > speed. In the case of my personal projects. Fortunately what you posted is also speedy :) – scx Dec 13 '14 at 22:21
2

You can use std::copy with an std::istream_iterator for std::cin and std::ostream_iterator for the std::stringstream.

#include <algorithm>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <sstream>

void redirect(std::ifstream &is, std::stringstream &os) {
    is >> std::noskipws;
    std::istream_iterator<char> begin(is);
    std::istream_iterator<char> end;
    std::ostream_iterator<char> out(os);
    std::copy(begin, end, out);
}

Note that this copies the entire file into the std::stringstream, and thus for really large files that can't fit in memory, this will fail. The rdbuf solution that NaCl gave will similarly have an issue with very large files.

You can solve the large file problem by not reading all of the input at once. However, this will most likely require you to restructure your code inside your parsers. Without more detail on their implementations, I can't point you in the right direction.

b4hand
  • 9,550
  • 4
  • 44
  • 49
  • I am not sure I get what you mean. Basically don't overload istream operator? – scx Dec 13 '14 at 21:58
  • Please do! I have a few spare keyboards, want me to mail one? :D – scx Dec 13 '14 at 22:01
  • 1
    `std::copy(std::istreambuf_iterator(ifs), std::istreambuf_iterator(), std::ostreambuf_iterator(db.iss));` – NaCl Dec 13 '14 at 22:05
  • 1
    You don't need to overload anything. – b4hand Dec 13 '14 at 22:09
  • Well the whole idea is to make it as elegant as possible. This way, I interact with different parser objects simply by doing something like: while(ss >> *database >> *gutenbargParser >> *reader) {} – scx Dec 13 '14 at 22:12
  • You can still overload for the parsers. – b4hand Dec 13 '14 at 22:27
  • Hmmm, so you suggest just a usual method that returns a ostringstream? I may try that, as I have to pipe an empty stringstream to get the overload working. – scx Dec 14 '14 at 07:17