从标准输入或文件中有条件地读取文件

3

我是一名新手C++程序员。我想要编写一个命令行应用程序,它接受两个参数,一个输入文件和一个输出文件。但是,如果输入文件或输出文件名为“-”,我需要程序读取/输出到标准输入/输出而不是文件。我的问题是,在C ++中执行此操作时,我不知道如何做到让编译器知道输入/输出流已初始化。以下是我的代码。

if(argv[1] == "-") {
  istream input;
  cout << "Using standard input" << endl;
}
else {
  ifstream input;
  cout << "Using input file " << argv[1] << endl;
  input.open(argv[1], ios::in);
  if(!input) {
    cerr << "Cannot open input file '" << argv[1]
    << "', it either does not exist or is not readable." << endl;
    return 0;
  }
}

if(argv[2] == "-") {
  ostream output;
  cout << "Using standard output" << endl;
}
else {
  ofstream output;
  cout << "Using output file " << argv[2] << endl;
  output.open(argv[2], ios::out);

  if(!output) {
    cerr << "Cannot open output file '" << argv[2] << "' for writing."
    << " Is it read only?" << endl;
    return 0;
  }
}

从这里开始,我无法在输入上调用运算符 >>,因为,我猜测,编译器不知道它是否被初始化。


我最近在这个链接(http://stackoverflow.com/a/9244559/596781)中发布了类似的内容。 - Kerrek SB
1
"argv[1] == "-""并不是你想象中的那样。你用的是哪一本C++书籍? - Lightness Races in Orbit
我一直在使用Bruce Eckel的《C++编程思想》,但我的大部分坏习惯来自于我的Java编程经验。 - Stegosaurus
2个回答

5

您可以使用一个流的引用,然后将其初始化为引用文件流或标准输入或输出。不过,初始化必须在单个命令中完成,因此即使您不使用文件流,也必须声明它们。

ifstream file_input;
istream& input = (strcmp(argv[1], "-") == 0) ? cin : file_input;

ofstream file_output;
ostream& output = (strcmp(argv[2], "-") == 0) ? cout : file_output;

注意在inputoutput的声明中出现了&符号。它们表示我们并没有声明一个独立的流对象,而只是声明了对其他某个流对象的引用,我们根据argv[x]的值有条件地进行选择。
然后,如果需要,您可以打开文件。缺点是我们需要两次检查“-”字符串,而不仅仅是每个输入或输出一次。
if (strcmp(argv[1], "-") == 0) {
  cout << "Using standard input" << endl;
} else {
  cout << "Using input file " << argv[1] << endl;
  file_input.open(argv[1]);
  if (!file_input) {
    cerr << "Cannot open input file '" << argv[1]
         << "', it either does not exist or is not readable." << endl;
    return 1;
  }
}

此后,您可以从input读取并写入output,文件或标准I/O流将被使用。
请注意我对您的代码所做的其他更改。首先,我调用strcmp而不是使用==运算符;当比较char*和字面量时,该运算符不会执行您想要的操作。接下来,当打开文件失败时,我返回1而不是0。零表示程序成功,而非零则告诉操作系统该程序失败了。

谢谢指出返回零的错误,我没有意识到。 - Stegosaurus

1

您可以在条件语句之外声明成员,因为ifstream继承了istream,而ofstream继承了ostream。为了避免切片问题,请使用指针:

istream* input = NULL;
bool isFile = false;
if(argv[1] == "-") {
  input = new istream;
}
else {
  input = new ifstream;
  isfile = true;
}

然后,无论您想在哪里使用input,您只需将其转换为正确的类型:

if (isFile)
{
    ifstream* finput = (ifstream*)input;
}

这不是唯一的解决方案;可能还有更简洁的方法

问题在于,你必须在条件语句块外部声明流,这样它就不会超出作用域,因为你想在外部使用它。


谢谢,我完全没有意识到 ifstream 继承自 istream! - Stegosaurus
不要忘记 delete。最好使用 shared_ptr 实现。 - Lightness Races in Orbit

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