C++公共接口:用于“cin”和“File”的统一操作方式

4

cin和文件输入有共同的接口吗?

我想编写一个带有可选参数的程序。

prog [input-file]

如果指定了输入文件,则应从文件中读取,如果没有指定,则应从cin中读取。
据我所知,它们都实现了“istream”。您如何设置它,以便我可以执行类似于“in >> var”的操作,其中“in”是一个“istream”。
4个回答

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
}

您可以将部分工作转移到助手类中,以使发生的情况更清晰(请注意,在文件无法打开的情况下,这会略有不同):
#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));
}

@Martin和@dave:虽然这当然是正确的,但我非常喜欢James的答案。将问题分解(决定从哪里读取而不是实际进行读取)成函数使代码更易于阅读。 - sbi
@sbi 这个分解怎么样? ;) - dave
首先,我不喜欢为算法引入类。算法最好实现为函数,而类适合存储对象,即:状态(成员数据)加上操作(成员函数)。选择流是一种算法。但这可能只是我的偏好。第二个问题就不容置疑了:如果无法打开文件,此代码将悄悄地从控制台读取。想象一下用户输错文件名,然后坐在那里盯着闪烁的提示符,不知道该怎么办! - sbi
@sbi,@James:经过考虑,我更喜欢James版本来处理简单类型的程序。但是如果需要解析大量命令行参数(通常不在主函数中完成),我需要再考虑一下。 - Martin York

7
你可以编写一个函数,该函数接受对 std::istream 的引用:
void do_input(std::istream& the_istream)
{
    int my_awesome_variable;
    the_istream >> my_awesome_variable;
}

使用示例:

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

    // reading from a file:
    std::ifstream fs("test.txt");
    do_input(fs);
}

1

我的两分意见:

#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;


}

只是一个小的风格问题...因为使用普通的c-strings时,==或!=比较将不起作用,所以当我比较它们时,我更喜欢显式地从c-string创建一个std::string。 - San Jacinto
@San Jacinto:我理解你在一般情况下的观点。但是我认为x == ""实际上比x == std::string("")更清晰。 - Martin York
那不应该是 !isFile.empty() 吗? - sbi

-1
istream& input = cin;

或者

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

然而,我认为这不是一个很好的方法,因为cin没有close(),而ifstream有。


1
你不能重新定向一个引用;即使你修复了明显的语法错误,input = inputFileStream 也无法工作。关于 close(),通常情况下你不需要调用 close();你只需让析构函数处理它。 - James McNellis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接