4

Is there a common interface for cin and file input?

I want to make a program that has an optional parameter

prog [input-file]

If an input file is specified, then it should read from the file, and if not, it should read from cin.

From what I can tell, they both implement istream. How would you set up it so that I could do something like in >> var, where in is an istream.

Verhogen
  • 27,221
  • 34
  • 90
  • 109

4 Answers4

8
#include <iostream>
#include <fstream>

int main(int argc, char **argv)
{
    std::ifstream f;
    if (argc >= 2) {
        f.open(argv[1]);
    }
    std::istream &in = (argc >= 2) ? f : std::cin;

    // use in here
}

You could shift some of this work into a helper class to make it clearer what's going on (note that this has slightly different behavior in the case where the file can't be opened):

#include <iostream>
#include <fstream>

class ifstream_or_cin_t {
    std::ifstream f;

public:
    ifstream_or_cin_t(const char *filename)
    {
        if (filename) {
            f.open(filename);
        }
    }

    operator std::istream &() { return f.is_open() ? f : std::cin; }
};

static void do_input(std::istream &in)
{
    // use in...
}

int main(int argc, char **argv)
{
    do_input(
        ifstream_or_cin_t((argc >= 2) ? argv[1] : NULL));
}
dave
  • 12,634
  • 3
  • 20
  • 12
  • @Martin & @dave: While this is certainly right, I very much prefer James answer. Decomposing problems (deciding where to read from vs. actually doing the reading) into functions makes code so much easier to read. – sbi Sep 25 '10 at 10:32
  • @sbi How's that for decomposition? ;) – dave Sep 25 '10 at 13:56
  • For one, I'm not a fan of introducing classes for algorithms. Algorithms are best implemented as functions, and classes are good suited to store objects, that is: a state (member data) plus operations (member functions). Picking a stream is an algorithm. But that might just be my preferences. The second problem is less disputable: if you can't open the file, this code will silently read from the console. Imagine a user mistyping a filename and then sitting and staring at the blinking prompt, not knowing what to make of it! – sbi Sep 25 '10 at 16:45
  • @sbi, @James: After thinking about it I do prefer James version for the simpler types of program. But I would need to think some more for situations where there were a large number of command line arguments that needed to be parsed (which you generally don't do in main). – Martin York Sep 25 '10 at 18:18
7

You can write a function that takes a reference to an std::istream:

void do_input(std::istream& the_istream)
{
    int my_awesome_variable;
    the_istream >> my_awesome_variable;
}

Usage example:

int main()
{
    // reading from stdin:
    do_input(std::cin);

    // reading from a file:
    std::ifstream fs("test.txt");
    do_input(fs);
}
James McNellis
  • 348,265
  • 75
  • 913
  • 977
1

My 2P worth:

#include <iostream>
#include <fstream>
#include <string>

extern char const* findFlag(int,char*[],char const*);
int main(int argc,char* argv[])
{
    std::string     isFile  = findFlag(argc,argv,"-f");
    std::ifstream   file;

    if (isFile != "")
    {   file.open(isFile.c_str());
    }
    std::istream&   data    = isFile != "" ? file : std::cin;


}
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • Just a minor stylistic point... Because with ordinary c-strings a == or != comparison will not work, I prefer to explicitly create an std::string from a c-string when I am comparing them. – San Jacinto Sep 25 '10 at 14:02
  • @San Jacinto: I understand your point in the general case. But I think x == "" is actually clearer than x == std::string(""). – Martin York Sep 25 '10 at 18:13
  • Wouldn't that better be `!isFile.empty()`? – sbi Sep 25 '10 at 20:37
-1
istream& input = cin;

or

inputFileStream ifstream(fileName);
istream& input = inputFileStream;

However I think that this is not a very good method since cin doesn't have a close() whereas ifstream does.

Novikov
  • 4,399
  • 3
  • 28
  • 36
  • 1
    You cannot retarget a reference; even if you fixed the glaring syntactic errors, `input = inputFileStream` cannot work. Concerning `close()`, usually you don't have to call `close()` anyway; you just let the destructor handle it. – James McNellis Sep 24 '10 at 23:54