2012-02-12 104 views
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; 
    } 
} 

在这里,我不能调用操作>>输入,因为,我猜,编译器不知道它已经初始化。

+0

我发布了一些有关[最近](http://stackoverflow.com/a/9244559/596781)的效果。 – 2012-02-12 17:42:35

+1

'argv [1] ==“ - ”'不会做你认为它做的事情。你正在使用哪一本C++书? – 2012-02-12 17:54:47

+0

我一直在使用Bruce Eckel的“Thinking in C++”,但我的大多数坏习惯都来自我的Java编程经验。 – Stegosaurus 2012-02-12 18:11:32

回答

4

您可以使用参考来创建一个流,然后初始化它以引用文件流或标准输入或输出。但是,初始化必须在单个命令中进行,因此即使不使用文件流,也必须声明文件流。

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.零表示成功程序,而非零表示程序失败。

+0

感谢您指出返回零的错误,我没有意识到这一点。 – Stegosaurus 2012-02-12 18:14:49

+0

刚试过,这个解决方案效果很好! – Stegosaurus 2012-02-12 18:34:50

1

您可以声明条件之外的成员,因为ifstream继承istreamofstream继承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; 
} 

这不是唯一的解决方案;有可能是更干净的

事情是,你必须在条件之外的块声明流,所以它不会超出范围,因为你想在外面使用它。

+0

谢谢,我完全没有意识到ifstream继承自istream! – Stegosaurus 2012-02-12 17:46:13

+0

不要忘记'删除'。理想情况下使用shared_ptr实现。 – 2012-02-12 17:53:56