Transparent read from stdin or a file in C++? - c++

I would like to parse either an stdin stream or a file. So I want a function/method to accept either of this.
Note that my goal is not to call read twice!
As istream is the base class for cin and ifstream` I should be able write this:
#include <iostream>
#include <fstream>
void read(std::istream &fp) {
while(!fp.eof()) {
std::string line;
std::getline(fp, line);
std::cout << line << std::endl;;
}
}
int main(int argc, char *argv[])
{
std::ifstream fp;
if (argc >= 2) {
fp.open(argv[1]);
if (!fp) abort();
}
else {
fp = std::cin;
}
read(fp);
if (fp.is_open()) {
fp.close();
}
return 0;
}
In C I can do the following with calling it with either read_content(stdin) or read_content(fp):
void read_content(FILE *file)
What is the proper way to do this in C++?

std::cin is an instance of std::istream and not derived from std::ifstream but the opposite is true.
Inheritance graph of Stream-based I/O:
(Taken from cppreference.com - Input/output library)
So, OPs intention can be performed using a reference or pointer to std::istream.
Demo:
#include <iostream>
#include <fstream>
void read(std::istream &fp) {
while(!fp.eof()) {
std::string line;
std::getline(fp, line);
std::cout << line << std::endl;;
}
}
int main(int argc, char *argv[])
{
std::ifstream fp;
std::istream &in = (argc >= 2)
? [&]() -> std::istream& {
fp.open(argv[1]);
if (!fp) abort();
return fp;
}()
: std::cin;
read(in);
if (fp.is_open()) {
fp.close();
}
return 0;
}
Compiled on coliru
Note:
while (!fp.eof()) {
should be replaced by
while (fp) {
The reason for this has been thoroughly discussed in
SO: Why is iostream::eof inside a loop condition (i.e. while (!stream.eof())) considered wrong?.

In C I can do the following with calling it with either read_content(stdin) or read_content(fp):
Yes, and in C++ you should just call either read(std::cin) or read(fp). It's exactly the same.
The line
fp = std::cin;
is the wrong thing to do, as std::cin is only declared as a std::istream. There is no std::ifstream constructor taking an istream, you don't want an independent object here anyway, and if std::cin is really an object of some type derived from std::ifstream, you'd slice it.

Related

How to read lines from a file as well as from std::cin?

I'm writing a program, which takes the lines of text to work with from the file, the name of which the user passes as an argument, e.g. program <name of the file>. But if the name is not provided, the input is taken dynamically from std::cin. What I've tried:
Redirecting the buffer (somewhy causes segfault)
if (argc == 2) {
std::ifstream ifs(argv[1]);
if (!ifs)
std::cerr << "couldn't open " << argv[1] << " for reading" << '\n';
std::cin.rdbuf(ifs.rdbuf());
}
for (;;) {
std::string line;
if (!std::getline(std::cin, line)) // Here the segfault happens
break;
Creating a variable, in which the input source is stored
std::ifstream ifs;
if (argc == 2) {
ifs.open(argv[1]);
if (!ifs)
std::cerr << "couldn't open " << argv[1] << " for reading" << '\n';
} else
ifs = std::cin; // Doesn't work because of the different types
for (;;) {
std::string line;
if (!std::getline(ifs, line))
break;
Now I'm thinking of doing something with file structures/descriptors. What to do?
UPD: I would like to have the possibility to update the input source in the main loop of the program (see below).
The seg fault in your first example is due to a dangling pointer; right after you call std::cin.rdbuf(ifs.rdbuf()), ifs is destroyed.
You should do what #NathanOliver suggests and write a function which takes an istream&:
#include <iostream>
#include <fstream>
#include <string>
void foo(std::istream& stream) {
std::string line;
while (std::getline(stream, line)) {
// do work
}
}
int main(int argc, char* argv[]) {
if (argc == 2) {
std::ifstream file(argv[1]);
foo(file);
} else {
foo(std::cin);
}
}

Return boost streambuf from function

I am trying to wrap up a code that read gz files into a function, source code is taken from https://techoverflow.net/2013/11/03/c-iterating-lines-in-a-gz-file-using-boostiostreams/
My try
boost::iostreams::filtering_streambuf<boost::iostreams::input> func(std::string filename);
boost::iostreams::filtering_streambuf<boost::iostreams::input> func(std::string filename)
{
std::ifstream file(filename, std::ios_base::in | std::ios_base::binary);
boost::iostreams::filtering_streambuf<boost::iostreams::input> inbuf;
inbuf.push(boost::iostreams::gzip_decompressor());
inbuf.push(file);
return inbuf;
}
void mymainfunc(std::string filename)
{
//Convert streambuf to istream
std::istream ifstrm( func( filename));
std::string line;
while(std::getline(ifstrm, line)) {
std::cout << line << std::endl;
}
}
Code runs fine if not run through the function, i am doing something wrong in the return type I think.
Error: https://pastebin.com/kFpjYG0M
Streams are not copyable. In fact, this filteringstreambuf is not even movable.
So in this case, you will want to dynamically allocate and return by smart-pointer. However, even just returning the filtering streambuf will not work, because it would hold a reference to the ifstream. And that's a local.
So, maybe you need to package it up:
Live On Coliru
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <fstream>
namespace bio = boost::iostreams;
struct MySource {
using fisb = bio::filtering_istreambuf;
struct State {
State(std::string filename) : ifs(filename, std::ios::binary) {
buf.push(bio::gzip_decompressor());
buf.push(ifs);
}
fisb buf;
std::ifstream ifs;
std::istream is { &buf };
};
std::unique_ptr<State> _state;
operator std::istream&() const { return _state->is; }
};
MySource func(std::string filename) {
auto inbuf = std::make_unique<MySource::State>(filename);
return {std::move(inbuf)};
}
#include <iostream>
void mymainfunc(std::string filename)
{
auto source = func(filename);
std::istream& is = source;
std::string line;
while(std::getline(is, line)) {
std::cout << line << std::endl;
}
}
int main(){
mymainfunc("test.cpp.gz");
}
Alternative #1
You can simplify that:
Live On Coliru
struct MySource {
struct State {
State(std::string filename) : ifs(filename, std::ios::binary) {
is.push(bio::gzip_decompressor());
is.push(ifs);
}
std::ifstream ifs;
bio::filtering_istream is;
};
std::unique_ptr<State> _state;
operator std::istream&() const { return _state->is; }
};
Not dealing with the streambuffer separately makes it simpler.
Alternative #2
Not copying the whole thing has its own elegance:
Live On Coliru
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <fstream>
#include <iostream>
void mymainfunc(std::istream& is) {
std::string line;
while(std::getline(is, line)) {
std::cout << line << std::endl;
}
}
namespace bio = boost::iostreams;
int main(){
std::ifstream ifs("test.cpp.gz", std::ios::binary);
bio::filtering_istream is;
is.push(bio::gzip_decompressor());
is.push(ifs);
mymainfunc(is);
}

Is there a good idiom to deal with alternative output streams?

I want to write a simple program that depending on the options passed it the executable will print the output to the screen or to a file. The program is simple.
#include<iostream>
int main(int argc, char* argv[]){
... process options...
std::ostream& out = ... // maybe std::cout, maybe a *new* std::ofstream;
out << "content\n";
}
Is there a good idiom to make out refer alternatively to std::cout or a file stream at runtime?
I tried with pointers, but it is horrible. I couldn't avoid using pointers (Not to mention that more ugly code is needed to delete the pointer later).
#include<iostream>
#include<ofstream>
int main(int argc, char* argv[]){
std::string file = argc>1?argv[1]:"";
std::clog << "file: " << file << '\n';
// if there is no argument it will print to screen
std::ostream* out = (file=="")?&std::cout:(new std::ofstream(file)); // horrible code
*out << "content" << std::endl;
if(out != &std::cout) delete out;
}
I don't know, perhaps there is some feature of C++ streams that allows this. Perhaps I have to use some kind of type erasure. The problem, I think, is that std::cout is something that already exists (is global), but std::ofstream is something that has to be created.
I managed to use open and avoid pointers but it is still ugly:
int main(int argc, char* argv[]){
std::string file = argc>1?argv[1]:"";
std::clog << "file: " << file << '\n';
std::ofstream ofs;
if(file != "") ofs.open(file);
std::ostream& out = (file=="")?std::cout:ofs;
out << "content" << std::endl;
}
My preference is to use streams with suitable stream buffers installed. Here is one way direct output to a file or to std::cout:
#include <iostream>
#include <fstream>
int main(int ac, char* av) {
std::ofstream ofs;
if (1 < ac) {
ofs.open(av[1]);
// handle errors opening the file here
}
std::ostream os(file? file.rdbuf(): std::cout.rdbuf());
// use os ...
}
So much over-engineering.
#include <iostream>
#include <fstream>
int main(int argc, char* argv[]) {
std::ofstream ofs(argc > 1 ? argv[1] : "");
std::ostream& os = ofs.is_open() ? ofs : std::cout;
// use os ...
}
A runtime binding of the desired stream will pretty much need to look like what you already have.
On the pointer issue, sure you can clean it up a bit... maybe something like this? This is assuming you only want to create the ofstream if the argument exists.
int main(int argc, char* argv[]){
std::string file = argc > 1 ? argv[1] : "";
std::clog << "file: " << file << '\n';
// if there is no argument it will print to screen
std::unique_ptr<std::ostream> fp;
if (file == "")
fp = std::make_unique<std::ofstream>(file);
std::ostream& out = (fp && fp->is_open()) ? std::cout : *fp; // not so horrible code
out << "content" << std::endl;
}
If the dynamic object is not required, the easiest may be something list this;
int main(int argc, char* argv[]){
std::string filename = (argc > 1) ? argv[1] : "";
std::ofstream file(filename);
// if there is no argument (file) it will print to screen
std::ostream& out = file.is_open() ? file : std::cout;
out << "content" << std::endl;
}
I often use something like this for command-line tools:
int main(int, char* argv[])
{
std::string filename;
// args processing ... set filename from command line if present
if(argv[1])
filename = argv[1];
std::ofstream ofs;
// if a filename was given try to open
if(!filename.empty())
ofs.open(filename);
// bad ofs means tried to open but failed
if(!ofs)
{
std::cerr << "Error opeing file: " << filename << '\n';
return EXIT_FAILURE;
}
// Here either ofs is open or a filename was not provided (use std::cout)
std::ostream& os = ofs.is_open() ? ofs : std::cout;
// write to output
os << "Some stuff" << '\n';
return EXIT_SUCCESS;
}
You could use a shared pointer to a stream for the polymorphic behavior:
#include <memory>
#include <fstream>
#include <sstream>
#include <iostream>
void nodelete(void*) {}
std::shared_ptr<std::ostream> out_screen_stream() { return std::shared_ptr<std::ostream>(&std::cout, nodelete); }
std::shared_ptr<std::ostream> out_file_stream() { return std::make_shared<std::ofstream>(); }
std::shared_ptr<std::ostream> out_string_stream() { return std::make_shared<std::ostringstream>(); }
int main ()
{
std::shared_ptr<std::ostream> out;
// case condition:
out = out_screen_stream();
out = out_file_stream();
out = out_string_stream();
*out << "content" << std::endl;
return 0;
}
Note: A std::shared_ptr allows managing different possible streams, where some streams should not get deleted (e.g.: std::cout).
Similar, but with std::unique_ptr:
#include <memory>
#include <fstream>
#include <sstream>
#include <iostream>
class Deleter
{
public:
Deleter(bool use_delete = true) : use_delete(use_delete) {}
template <typename T>
void operator () (const T* p) {
if(use_delete)
delete p;
}
bool nodelete() const { return ! use_delete; }
private:
bool use_delete;
};
using unique_ostream_ptr = std::unique_ptr<std::ostream, Deleter>;
unique_ostream_ptr out_screen_stream() { return unique_ostream_ptr(&std::cout, false); }
unique_ostream_ptr out_file_stream() { return unique_ostream_ptr{ new std::ofstream }; }
unique_ostream_ptr out_string_stream() { return unique_ostream_ptr{ new std::ostringstream }; }
int main ()
{
unique_ostream_ptr out;
// case condition:
out = out_screen_stream();
out = out_file_stream();
out = out_string_stream();
*out << "content" << std::endl;
return 0;
}
Maybe a reference?
#include<iostream>
#include<ofstream>
int main(int argc, char* argv[])
{
auto &out = std::cout;
std::ofstream outFile;
std::string fileName = argc>1?argv[1]:"";
std::clog << "file: " << file << '\n';
// if there is no argument it will print to screen
if(!fileName.empty())
{
outFile.open(fileName);
out = outFile;
}
out<<"one, one, two";
return 0;
}

How to output file in function in c++?

I want to output "a" to the file in the function, how do I do it? The following gives me error.
#include <iostream>
#include <fstream>
using namespace std;
void outputfile(const char* file);
int main()
{
int a = 1;
ofstream cc;
cc.open("123.txt");
if (cc.fail())
{
cout << "\nError in file opening" << endl;
return(1);
}
outputfile("123.txt");
cc.close();
return 0;
}
void outputfile(const char* file)
{
// I want to output a to the file, how can I do it? The following gives me error.
file << a;
}
The problem is solved, thanks for answering the question.:)
I see couple of issues that need to be addressed.
You can either pass the name of the file to outputfile or the ofstream. If you pass the name of the file to outputfile, the file needs to be opened in outputfile, not in main.
There are pros and cons to the two approaches. If the name of the file is passed to outputfile, main becomes very simple. However, if the ofstream object needs to be used to make other function calls, it will be better to pass an ofstream as the argument to outputfile.
If a ofstream is passed to outputfile, outputfile becomes very simple. However, if the ofstream is not going to be used by main for anything else, it is better to leave the details of what mechanism used by outputfile to write the data out. outputfile can even resort to FILE* and fprintf without affecting main.
a needs to be made available to outputfile. It can be made a global variable or be passed to outputfile. It is better to avoid global data. Hence, prefer to pass it as an argument.
Solution 1
Pass an ofstream to outputfile, in addition to a.
#include <iostream>
#include <fstream>
using namespace std;
void outputfile(std::ofstream& file, int a);
int main()
{
int a = 1;
ofstream cc;
cc.open("123.txt");
if (cc.fail())
{
cout << "\nError in file opening" << endl;
return(1);
}
outputfile(cc, a);
// No need. The file will be closed when the function returns.
// cc.close();
return 0;
}
void outputfile(std::ofstream& file, int a)
{
file << a;
}
Solution 2
The details of opening and closing the file is left to outputfile. Here, outputfile uses ofstream.
#include <iostream>
#include <fstream>
using namespace std;
void outputfile(char const* file, int a);
int main()
{
int a = 1;
outputfile("123.txt", a);
return 0;
}
void outputfile(char const* file, int a)
{
ofstream cc(file);
if (cc.fail())
{
cout << "\nError in file opening" << endl;
return;
}
cc << a;
}
Solution 3
The details of opening and closing the file is left to outputfile. Here, outputfile uses FILE*.
#include <iostream>
#include <fstream>
using namespace std;
void outputfile(char const* file, int a);
int main()
{
int a = 1;
outputfile("123.txt", a);
return 0;
}
void outputfile(char const* file, int a)
{
FILE* fp = fopen(file, "w");
if ( fp == NULL )
{
cout << "\nError in file opening" << endl;
return;
}
fprintf(fp, "%d", a);
fclose(fp);
}
At first, you have declared a in main(). Either you have to pass it as parameter or you have to take it global. I took global in the code below.
Then what do you do passing const char*? You have to write in file, so send the stream instead like below:
#include <iostream>
#include <fstream>
using namespace std;
void outputfile(ofstream &file); int a=1;
int main() {
ofstream cc;
cc.open("123.txt");
if (cc.fail()) {
cout <<"\nError in file opening" << endl;
return(1);
}
outputfile(cc);
cc.close();
return 0;
}
void outputfile(ofstream &file)
{
// I want to output a to the file, how do I do it? The following gives me error.
file << a;
}
a isn't in scope. Either declare it outside of main() in global space, or pass it into outputfile, something like:
void outputfile(ofstream &file file, int a) {
file << a;
}

how to read command output line by line in gcc in windows just as with the standard input?

This is what I tried:
#include <iostream>
#include <string>
int main(int argc, char const *argv[]) {
using namespace std;
for (string cin_line; getline(cin, cin_line);) {
cout << cin_line << endl;
}
FILE* pipe = popen("app.exe", "r");
for (string result_line; getline(pipe, result_line);) {
cout << result_line << endl;
}
pclose(pipe);
return 0;
}
It doesn't compile, the result is:
no matching function for call to 'getline(FILE*&, std::__cxx11::string&)'
Second example I've found here: https://stackoverflow.com/a/10702464/393087
But it seems mingw doesn't have pstream included: fatal error: pstream.h: No such file or directory - edit: ok I know, I missed that this is not a GCC library, it is named like it was but this is separate download: http://pstreams.sourceforge.net/
I know how to do it using buffer and get whole output on single line (like here: https://stackoverflow.com/a/478960/393087 ) then explode the line by \n and get my array, but the point here is that I must provide the output as soon as the input comes in.
Also I tried example from here: https://stackoverflow.com/a/313382/393087 - I've added main function to that:
#include <cstdio>
#include <iostream>
#include <string>
int main(int argc, char const *argv[]) {
using namespace std;
FILE * fp ;
if((fp= popen("/bin/df","r")) == NULL) {
// error processing and exit
}
ifstream ins(fileno(fp)); // ifstream ctor using a file descriptor
string s;
while (! ins.eof()){
getline(ins,s);
// do something
}
return 0;
}
This also doesn't compile:
error: variable 'std::ifstream ins' has initializer but incomplete type
ifstream ins(fileno(fp)); // ifstream ctor using a file descriptor
You can't do this:
FILE* pipe = popen("app.exe", "r");
for (string result_line; getline(pipe, result_line);) {
cout << result_line << endl;
}
pclose(pipe);
You need to do this:
#include <boost/noncopyable.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
FILE* pipe = popen("app.exe", "r");
boost::iostreams::file_descriptor_source
source(fileno(pipe), boost::iostreams::never_close_handle);
boost::iostreams::stream<boost::iostreams::file_descriptor_source>
stream(source, 0x1000, 0x1000);
string result_line;
while (getline(stream, result_line)) {
cout << result_line << endl;
}
:)