在更改文件描述符 1 以引用不同的文件后,我应该如何管理 ::std::cout?
How should I manage ::std::cout after changing file descriptor 1 to refer to a different file?
我想做 dup2(fd, 1); close(fd);
并让 ::std::cout
写入新的 fd 1。我怎样才能重置 ::std::cout
的状态,所以没有什么有趣的?例如,预先冲洗是否足够?或者还有更多事情要做?
我也很好奇 ::std::cin
。
如果您更改了它们在它们下面使用的文件描述符,是否有用于重置它们的标准机制?
明确地说,我的目标基本上是将我自己的输入和输出重定向到其他地方。我不想让进程无意中在其 parent 的标准输出上打嗝或试图从其 parent 的标准输入中消耗任何东西。我再也不想碰我的 parent 的标准输入或标准输出了。我想忘记他们曾经存在过。
我尤其不想无意中将输出发送到我 parent 在不同文件描述符上使用的同一设备。
我的目标是让 cin 和 cout 通向与进程开始时完全不同的地方,并且永远不会以任何方式触及它们过去通向的地方。曾经!
您可以为 socket_streambuf class 创建(或使用现有的)库并将其关联到 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 流缓冲区的状态而烦恼。
选项 1:设置标准输入和标准输出
By default, all eight standard C++ streams are synchronized with their respective C streams.
只要您没有明确调用 sync_with_stdio(false)
,它们就会保持这种状态。这是什么意思?以下:
In practice, this means that the synchronized C++ streams are unbuffered, and each I/O operation on a C++ stream is immediately applied to the corresponding C stream's buffer. This makes it possible to freely mix C++ and C I/O.
所以,flush()
-ing 你的 cin
和 cout
在 dup()
-ing 之前就足够了,因为它们应该处于一致的状态。
例如,如果您希望使用文件,您可以使用:
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
os 的结构。在此更改之前的任何时刻复制此指针的任何模块将继续使用旧的 FILE
。一个具体的例子是 libc++ 对 cout
的实现,它在对象的初始化期间将 FILE * stdout
复制到私有成员。另一方面,freopen
更改 OS 的内部 FILE
结构以使用新打开的文件,影响任何拥有 FILE *
的人。
注意 2: 当使用 dup()
风格(而不是 freopen()
)时,我们正在改变基础 fd
,而不是FILE*
。 freopen()
方法的作用不止于此。来自 POSIX:
The freopen() function shall first attempt to flush the stream associated with stream as if by a call to fflush(stream). Failure to flush the stream successfully shall be ignored. If pathname is not a null pointer, freopen() shall close any file descriptor associated with stream. Failure to close the file descriptor successfully shall be ignored. The error and end-of-file indicators for the stream shall be cleared.
dup()
-ing 可能有效,但是,它可能棘手,因为它won't affect other properties of the FILE*
,包括:字符宽度,缓冲状态,缓冲区,I/O,Binary/text模式指示器,文件结束状态指示器,错误状态指示器,文件position indicator & (After C++17) Reentrant lock used to prevent data races.
当possible时,我建议使用freopen
。否则,您可以按照自己描述的步骤进行操作 (fflush()
、clearerr()
)。跳过 fclose()
是明智的,因为我们无法通过任何 API 方法重新打开相同的内部 FILE
。
选项2:设置cin的&cout的rdbuf()
反过来,就像一些评论 proposed 一样,正在使用 rdbuf()
替换 cin
和 cout
的底层缓冲区。
你有什么选择?
文件流: 打开 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);
自定义流: 为 std::streambuf
使用您自己的自定义包装器。请参阅示例 here.
我想做 dup2(fd, 1); close(fd);
并让 ::std::cout
写入新的 fd 1。我怎样才能重置 ::std::cout
的状态,所以没有什么有趣的?例如,预先冲洗是否足够?或者还有更多事情要做?
我也很好奇 ::std::cin
。
如果您更改了它们在它们下面使用的文件描述符,是否有用于重置它们的标准机制?
明确地说,我的目标基本上是将我自己的输入和输出重定向到其他地方。我不想让进程无意中在其 parent 的标准输出上打嗝或试图从其 parent 的标准输入中消耗任何东西。我再也不想碰我的 parent 的标准输入或标准输出了。我想忘记他们曾经存在过。
我尤其不想无意中将输出发送到我 parent 在不同文件描述符上使用的同一设备。
我的目标是让 cin 和 cout 通向与进程开始时完全不同的地方,并且永远不会以任何方式触及它们过去通向的地方。曾经!
您可以为 socket_streambuf class 创建(或使用现有的)库并将其关联到 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 流缓冲区的状态而烦恼。
选项 1:设置标准输入和标准输出
By default, all eight standard C++ streams are synchronized with their respective C streams.
只要您没有明确调用 sync_with_stdio(false)
,它们就会保持这种状态。这是什么意思?以下:
In practice, this means that the synchronized C++ streams are unbuffered, and each I/O operation on a C++ stream is immediately applied to the corresponding C stream's buffer. This makes it possible to freely mix C++ and C I/O.
所以,flush()
-ing 你的 cin
和 cout
在 dup()
-ing 之前就足够了,因为它们应该处于一致的状态。
例如,如果您希望使用文件,您可以使用:
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
os 的结构。在此更改之前的任何时刻复制此指针的任何模块将继续使用旧的 FILE
。一个具体的例子是 libc++ 对 cout
的实现,它在对象的初始化期间将 FILE * stdout
复制到私有成员。另一方面,freopen
更改 OS 的内部 FILE
结构以使用新打开的文件,影响任何拥有 FILE *
的人。
注意 2: 当使用 dup()
风格(而不是 freopen()
)时,我们正在改变基础 fd
,而不是FILE*
。 freopen()
方法的作用不止于此。来自 POSIX:
The freopen() function shall first attempt to flush the stream associated with stream as if by a call to fflush(stream). Failure to flush the stream successfully shall be ignored. If pathname is not a null pointer, freopen() shall close any file descriptor associated with stream. Failure to close the file descriptor successfully shall be ignored. The error and end-of-file indicators for the stream shall be cleared.
dup()
-ing 可能有效,但是,它可能棘手,因为它won't affect other properties of the FILE*
,包括:字符宽度,缓冲状态,缓冲区,I/O,Binary/text模式指示器,文件结束状态指示器,错误状态指示器,文件position indicator & (After C++17) Reentrant lock used to prevent data races.
当possible时,我建议使用freopen
。否则,您可以按照自己描述的步骤进行操作 (fflush()
、clearerr()
)。跳过 fclose()
是明智的,因为我们无法通过任何 API 方法重新打开相同的内部 FILE
。
选项2:设置cin的&cout的rdbuf()
反过来,就像一些评论 proposed 一样,正在使用 rdbuf()
替换 cin
和 cout
的底层缓冲区。
你有什么选择?
文件流: 打开
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);
自定义流: 为
std::streambuf
使用您自己的自定义包装器。请参阅示例 here.