C++ Piping ifstream into stringstream - c++

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>'))

Simply do this:
if(ifs){
db.iss << ifs.rdbuf();
ifs.close();
}

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.

Related

Changing the ifstream >> operator behaviour in C++

I am trying to understand how reading from a file using ifstream in C++ can be modified to work as needed. Right now, from my understanding, a single string is read if I use an std::string, where the definition of a string is text delimited by whitespace.
So this would read the work "this" into my std::string.
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::string fname("file.txt");
std::string data;
std::ifstream myfile(fname);
myfile >> data;
myfile.close();
std::cout << "read from file: " << data << std::endl;
exit(0);
}
If file.txt contained the line "this is a string".
What I am wondering, and cannot find, is if I can modify the behaviour of the >> operator, or possibly overload it in a custom class, to change the delimiter. For example, I could read an entire line until a \n is found. I could read delimiting by commas in a CSV file.
Etc.
Is this possible? I'm used to working in C and Python, and my C++ is rather weak.
Thanks.

Why can I overload istream's operator>> for strings?

Suppose I wanted operator>> to extract entire lines from an istream instead of whitespace-separated words. I was surprised to see that this, although horrible, actually worked:
#include <iostream>
#include <string>
namespace std {
istream &operator>>(istream &is, string &str) {
getline(is, str);
}
}
int main() {
std::string line;
std::cin >> line;
std::cout << "Read: '" << line << "'\n";
}
If I type multiple words into stdin, it actually does call my operator and read an entire line.
I would expect this definition of operator>> to conflict with the official one, producing a link error. Why doesn't it?
Edit: I thought maybe the real operator>> was a template, and non-template functions take precedence, but this still works just as well:
namespace std {
template<typename charT>
basic_istream<charT> &operator>>(basic_istream<charT> &is, basic_string<charT> &s) {
getline(is, s);
}
}
It happens to work because the official template is less specific (there are additional template arguments).
However it is Undefined Behaviourâ„¢. You are only permitted to provide overloads of standard library symbols for your own types. If you come across another standard library that will define extra overloads (it may), it will stop working and you won't know why.

Overload cin to take ifstream instead of char* fname? [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I am trying to create a file manipulator so when I cin >> filename it will read the file and cout the value... of course I am going add more stuffs but I would like to proceed with the basic of getting the content of the file.
What I wanna achieve is by cout prompting user for a textfile name, then when he enter, I will do another cin >> readfile on next line of code then the compiler will run the operator overload and cout the content.
How do I achieve it. Below is my code.
Question is instead of taking in char* fname, can I send ifstream in instead
so I can do something like
ifstream infile(filename.c_str());
cin >> infile
Below is my current code
#include <iostream>
#include <fstream>
#include <string>
#include "point2d.cpp"
#include "line2d.cpp"
#include <iomanip>
using namespace std;
struct myself
{
string myname;
};
istream &operator>> (istream &stream, myself &myself )
{
cout << "Enter my name";
stream >> myself.myname;
return stream;
}
istream &operator>> (istream &in, char* fname)
{
ifstream inFile;
inFile.open(fname);
char ch1;
while (inFile.get(ch1))
{
cout << ch1;
}
}
int main()
{
string filename;
cout << "Enter file name: ";
cin >> filename;
// was thinking of
// ifstream infile(filename.c_str());
// then read infile with cin
//how do i cin filename and read its content.
return 0;
}
You are messing up some concepts here. Your question is so vague, I'm not convinced that you are clear on what you want to do.
As far as I understand, you want
cin >> istream;
To do the following:
Read a file name
Open the file for reading
replace cin with the input stream for the file
Is that correct?
IMHO this is a bad idea, because by conventions cin >> should not modify cin in any significant manner. Sure, it will advance the stream, and there are hacks to change the parsing mode.
If you replace the stream with a new stream, make this obvious, don't try to hide it in some >> construct.
Programming is not a sport of saving characters. Your program won't be faster if you make it more cryptic. Good programmers write code that is very clear on what it does, to avoid errors, and make it easier to find them.
istream* input = &cin; // Default input is stdin
*input >> filename; // read filename
input = new istream(filename, istream::in);
// Continue to use *input
// Clean up input, if you replaced it:
// You might want to use a boolean flag instead of this hack.
if (input != &cin) {
delete input;
}
I'm afraid you are quite confused here. cin does not read anything; you read from cin. So you might want to overload operator >> somehow to read the contents of cin into a file, but not the other way around.
What you can do is overload operator << so it outputs the contents of a file into an output stream, such as cout. The following, nevertheless, is invalid:
ostream& operator<<(ostream& out, char* filename);
You cannot define this operator because it is already defined. You need to write a class that represents a file name and overload the operator on that. A simple version:
struct Filename
{
Filename(const string& filename) : filename_(filename) {}
string filename_;
};
ostream& operator<<(ostream& out, const Filename& name)
{
// read the file whose name is name.filename_
}
And you can call it this way:
cout << Filename("filename.ext");
You are doing several bad practices all at once.
First, cin is an istream, so you are looking to overload an istream operator to take an istream. That will be incredibly confusing for anyone trying to read your code.
Second, a function should do 1 job (that is, you should not try to hide functionality by lumping several distinct tasks into 1 function). istream reads data from an input stream (in this case, the file name you want to open). You will then need to pass that file name to an ifstream instance to actually read the file. Presumably you want to output it, in which case you would use an ostream (e.g. cout).
The entire logic you are looking to implement can be done in roughly 5 lines of code or less:
string filename = "";
cin >> filename;
ifstream fin(filename.c_str(), ifstream::in);
copy(istreambuf_iterator<char>(fin), istreambuf_iterator<char>(), ostreambuf_iterator<char>(cout));
Which is much shorter and more readable than what you are trying to do.

Why does std::copy (from istream to ostream) raises an ios::failure exception?

The following code should copy data from an wifstream to wcout.
After the content is copied, the program throws a ios::failure exception.
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <locale>
#include <iterator>
#include <algorithm>
int main(void)
{
std::locale::global(std::locale(""));
std::wifstream is;
is.exceptions( std::ios::failbit | std::ios::badbit );
is.open("test.ts", std::ios::binary);
is >> std::noskipws;
std::istream_iterator<wchar_t, wchar_t> in(is);
std::istream_iterator<wchar_t, wchar_t> end;
std::copy(in, end,
std::ostream_iterator<wchar_t, wchar_t>(std::wcout));
return 0;
}
The stream should only throw an exception (see exception mask) if anything goes bad, but not on EOF.
To avoid skipping white space use the std::istreambuf_iterator
std::copy(std::istreambuf_iterator<wchar_t, wchar_t>(is),
std::istreambuf_iterator<wchar_t, wchar_t>(),
std::ostream_iterator<wchar_t, wchar_t>(std::wcout));
The exception:
The local may be using codecvt facet that is failing.
Try commenting out the locale line see what happens.
Have you tried to print what the exceptions is?
try
{
// do work
}
catch(std::exception const& e)
{
std::cout << e.what() << "\n";
}
Because you're using std::istream_iterator, the attempt to read a character past the end of the stream sets both eofbit and failbit (and only after some error bits are set, does the iterator become equal to the end iterator)
Stripping to bare essentials and reverting to char to make it even simpler, program is equivalent to:
#include <iostream>
#include <fstream>
int main()
{
std::ifstream is("test.txt", std::ios::binary);
is.exceptions(std::ios::failbit); // failbit only because that's what you get
is >> std::noskipws;
if(is)
for(char c; is >> c;) // will throw!
std::cout << c;
}
According to §27.6.1.2.3/10:
After a sentry object is constructed a character is extracted from in, if one is available, and stored in c. Otherwise, the function calls in.setstate(failbit).
So, when it reaches the end of the file and can no longer extract a character, it will set the fail bit, which you've set to produce an exception. Using std::copy doesn't change the behavior -- an istream_iterator reads via operator>>.
You can copy the file a bit more easily:
std::wifstream is("test.ts", std::ios::binary);
std::wcout << is.rdbuf();

Read 1 line from istream to string stream without temporary variable in C++?

Is is possible to read one line from input stream and pass it to string stream without using temorary string variable in C++?
I currently do the reading like this (but I don't like the temporary variable line):
string line;
getline(in, line); // in is input stream
stringstream str;
str << line;
Like #Steve Townsend said above, it's probably not worth the effort, however if you wanted to do this (and you knew beforehand the number of lines involved), you could do something like:
#include <iostream>
#include <iterator>
#include <string>
#include <sstream>
#include <algorithm>
using namespace std;
template <typename _t, int _count>
struct ftor
{
ftor(istream& str) : _str(str), _c() {}
_t operator() ()
{
++_c;
if (_count > _c) return *(_str++); // need more
return *_str; // last one
}
istream_iterator<_t> _str;
int _c;
};
int main(void)
{
ostringstream sv;
generate_n(ostream_iterator<string>(sv, "\n"), 5, ftor<string, 5>(cin));
cout << sv.str();
return 0;
}
There is detailed info in the question below (per #Martin York) on reading direct from stream to stringstream. This is not a direct dup as you wish to handle the input line by line, but this approach will be hard to beat for efficiency. You can instantiate the individual lines using a character range once the raw data is in the stringstream.
How to read file content into istringstream?
To be honest, this may be a lot of work for a problem that's not really a huge perf concern anyway.