代码之家  ›  专栏  ›  技术社区  ›  Omnifarious

在将文件描述符1更改为引用其他文件后,我应该如何管理::std::cout?

  •  6
  • Omnifarious  · 技术社区  · 7 年前

    我想做 dup2(fd, 1); close(fd); ::std::cout 写信给新的fd 1。如何重置的状态 :std::cout

    我也很好奇 ::std::cin .

    如果您更改了它们下面使用的文件描述符,是否有标准机制来重置它们?

    需要明确的是,我的目标基本上是将我自己的输入和输出重定向到其他地方。我不想让这个过程无意中在它父母的stdout上打嗝,或者试图从它父母的stdin中消费任何东西。我再也不想碰我父母的stdin或stdout了。我想忘记他们曾经存在过。

    我尤其不想无意中将输出发送到我父母在不同文件描述符上使用的同一设备。

    我的目标是让cin和cout走向与流程开始时完全不同的地方,并且永远不要接触他们曾经领导过的地方。曾经

    2 回复  |  直到 7 年前
        1
  •  6
  •   Daniel Trugman    7 年前

    选项1:设置标准输入(&D);stdout公司

    根据 cppreference.com :

    默认情况下,所有八个标准C++流都与其各自的C流同步。

    只要你没有打电话 sync_with_stdio(false) ,他们会一直这样。这是什么意思?以下内容:

    实际上,这意味着同步的C++流是无缓冲的,C++流上的每个I/O操作都会立即应用到相应C流的缓冲区。这使得可以自由混合C++和C I/O。

    所以 flush() -ing您的 cin cout 之前 dup() -因为它们应该处于一致的状态,所以对它们进行初始化就足够了。

    if (freopen("input.txt", "r", stdin) == NULL) {
        // Handle error, errno is set to indicate error
    }
    
    if (freopen("output.txt", "w", stdout) == NULL) {
        // Handle error, errno is set to indicate error
    }
    

    注1: 设置全局 extern FILE * stdin stdout 不会工作,因为它只是更改指向相关 FILE 操作系统的结构。在此更改之前的任何时刻复制此指针的任何模块都将继续使用旧的 文件 库特 ,哪些副本 FILE * stdout 在对象初始化期间发送给私有成员。 freopen 另一方面,改变了内部 文件 FILE * 对它。

    注2: 使用时 dup() freopen() ),我们正在改变基础 fd FILE* . 这个 POSIX :

    dup() -ing公司 工作 但是 棘手的 won't affect other properties of the FILE* ,包括:字符宽度、缓冲状态、缓冲区、输入/输出、二进制/文本模式指示器、文件结束状态指示器、错误状态指示器、文件位置指示器和;(C++17之后)用于防止数据竞争的可重入锁。

    如果可能,我建议使用 弗雷奥普 fflush() , clearerr() ). 跳过 fclose() 这将是明智的,因为我们将无法重新打开相同的内部 文件 通过任何API方法。

    选项2:设置cin&cout的rdbuf()

    另一方面,正如一些评论所提出的那样,正在取代 cin公司 的和 库特 rdbuf() .

    你在这里有什么选择?

    • 文件流: 打开 ifstream & ofstream 并使用它们:

      std::ifstream fin("input.txt");
      if (!fin) {
          // Handle error
      }
      cin.rdbuf(fin.rdbuf());
      
      std::ofstream fout("output.txt");
      if (!fout) {
          // Handle error
      }
      cout.rdbuf(fout.rdbuf());
      
    • 网络流: 使用boost boost::asio::ip::tcp::iostream (它来自 std::streambuf

      boost::asio::ip::tcp::iostream stream("www.boost.org", "http");
      if (!stream) {
          // Handle error
      }
      
      cin.rdbuf(stream.rdbuf());
      cout.rdbuf(stream.rdbuf());
      
      // GET request example
      
      cout << "GET /LICENSE_1_0.txt HTTP/1.0\r\n";
      cout << "Host: www.boost.org\r\n";
      cout << "Accept: */*\r\n";
      cout << "Connection: close\r\n\r\n";
      cout.flush();
      
      std::string response;
      std::getline(cin, response);
      
    • 自定义流: 使用您自己的自定义包装器 标准::streambuf here

        2
  •  2
  •   Jodocus    7 年前

    您可以为socket\u streambuf类创建(或使用现有)库,并将其与std::cout/std::cin关联:

    socket_streambuf<char> buffer{ "127.0.0.1:8888" }; // will call socket(), connect() or throw on failure
    std::cout.rdbuf(&buffer); // re-direct cout to the network connection
    std::cout << "Hello, World!\n"; // may call send() on basic_streambuf::overflow()
    

    这样,您就不必费心操纵(全局)C流缓冲区的状态。