C++流的freopen()等效函数是什么?

21
在使用c风格的输入输出编程时,有时我会使用freopen()来重新打开stdin以进行测试,这样我就不必一遍又一遍地重新输入。我想知道是否有类似于c++输入输出流的等效方法。此外,我知道可以使用管道在命令行/终端/任何其他地方重定向它,但我想知道是否有一种方法可以在我的代码中完成(因为你可以看到,我对cl/t/w并不是很了解)。

当您拥有相同流的两个文件描述符时,您是否可以读取相同的数据两次?如果不能,则始终可以在C++中使用多个std::cin实例。 - Jonas Bötel
可能是如何将cin和cout重定向到文件?的重复问题。 - Vadzim
3个回答

43

freopen 函数也适用于 cincout,无需寻找其他替代品。

freopen("input.txt", "r", stdin); // redirects standard input
freopen("output.txt", "w", stdout); // redirects standard output

int x;
cin >> x; // reads from input.txt
cout << x << endl; // writes to output.txt

编辑: 来自C++标准27.3.1:

对象cin控制与对象stdin相关联的流缓冲区的输入,这在<cstdio>中声明。

因此根据标准,如果我们重定向stdin也会重定向cin。对于cout也是如此。


仅仅因为某个实现在一个环境下能够工作,并不意味着它是有效的 C++。最近我检查过,至多只能确定在 stdio 的更改是否会在相应的 iostream 中可见,反之亦然,甚至可能更糟。 - R.. GitHub STOP HELPING ICE
1
@R.. 来自 cplusplus.com 的解释:cin 是 istream 类的一个对象,代表标准输入流。它对应于 cstdio 流 stdin。 因此,cin 与 stdin 相关联,如果我们重定向了 stdin,那么也会重定向 cin。同样的道理也适用于 cout。http://www.cplusplus.com/reference/iostream/cin/ - UmmaGumma
嗯,这似乎可行,但是有没有一种只使用C++风格的输入特性来完成它呢? - flight
@quasiverse 我不这么认为。即使是 Timus 在线评测系统也建议在 C++ 中使用 freopen 进行测试。http://acm.timus.ru/help.aspx?topic=cpp - UmmaGumma
1
@R..GitHubSTOPHELPINGICE 你可以通过使用 std::sync_with_stdio(false); 来禁用这种行为,这样 C++ 就可以自己进行缓冲。如果你使用了 std::sync_with_stdio(false),你仍然可以重定向 std::cout,请参见这个相关问题的答案 - yyny
显示剩余4条评论

14
#include <iostream>
#include <fstream>

int main() {

  // Read one line from stdin
  std::string line;
  std::getline(std::cin, line);
  std::cout << line << "\n";

  // Read a line from /etc/issue
  std::ifstream issue("/etc/issue");
  std::streambuf* issue_buf = issue.rdbuf();
  std::streambuf* cin_buf = std::cin.rdbuf(issue_buf);
  std::getline(std::cin, line);
  std::cout << line << "\n";

  // Restore sanity and read a line from stdin
  std::cin.rdbuf(cin_buf);
  std::getline(std::cin, line);
  std::cout << line << "\n";
}

http://www.cplusplus.com/reference/iostream/ios/rdbuf/


1

这篇新闻组帖子探讨了您的选择。

这取决于系统,发帖人没有指明系统,但cin.clear()应该可以工作。我已经在一个UNIX系统上测试了附加的程序,使用的是AT&T版本的iostreams。

#include <iostream.h>
int main()
{
    for(;;) {
        if ( cin.eof() ) {
            cout << "EOF" << endl;
            cin.clear();
        }
        char c ;
        if ( cin.get(c) ) cout.put(c) ;
    }
} 

在cfront和TC++中,这是可以正常工作的。但在首次出现问题的g++中,需要进行额外的操作:
  cin.clear();
  rewind ( _iob ); // Seems quite out of place, doesn't it?
                   // cfront also accepts but doesn't
                   // require this rewind. 

虽然我注意到这是在1991年,但它仍然有效。记得使用现在标准的头文件,而不是。

(顺便说一下,我用谷歌搜索词“reopen cin c++”找到了这篇文章,第二个结果。)

让我们知道你的进展如何。你也可以使用。


混合使用C标准输入输出和C++输入输出流是无效的,会导致实现定义或未定义的行为。 - R.. GitHub STOP HELPING ICE
抱歉,我不太明白这与我的问题有什么关系。您能再解释一下吗? - flight
@quasiverse:这是关于通过 cin 重新打开 STDIN 的问题。 - Lightness Races in Orbit
@R:我也很担心。那么没有UB的情况下,无法满足OP的要求。 - Lightness Races in Orbit

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