在Windows上重定向标准I/O会更加复杂,因为缺少一个合适的接口来映射任意Win32文件句柄和更高层的文件描述符/流之间的关系。
实际上,在Windows上有三个不同的I/O层:
- 标准C I/O流(这些是由
printf
,scanf
等使用的) - POSIX I/O描述符(这些是
read
,write
等使用的整数) - Win32 API I/O句柄(由
ReadFile
,WriteFile
等使用)
重定向C流
要重定向C流,您可以使用freopen
。例如,您可以使用以下命令重定向C stdout
:
freopen("log.txt", "w", stdout);
这种重定向通常不会重定向 POSIX 或 Win32 API 的 I/O(如果有的话,它们仍然会读取/写入附加的控制台)。此外,这种重定向不会被子进程继承。(在符合 POSIX/非 Windows系统上,通常 POSIX API 也是系统 API,C API 是在 POSIX API 之上实现的。在这些情况下,freopen
已经足够了。)
重定向 POSIX I/O 描述符
要在 POSIX API 级别上重定向 I/O,可以使用 dup2
。例如,您可以重新指定文件描述符 STDOUT_FILENO
来重定向 stdout
,类似于:
int fd = open("log.txt", O_WRONLY);
dup2(fd, STDOUT_FILENO);
close(fd);
很遗憾,在Windows上,即使在POSIX API级别进行重定向也不能保证在C或Win32 API级别上进行重定向。这是否有效取决于C库实现所投入的工作,以映射POSIX文件描述符和Win32文件句柄(假设使用的C运行时库从一开始就在POSIX之上进行了I/O层)。还不能保证此重定向将被生成的子进程继承。
在Windows上重定向标准I / O!
要在Windows上正确重定向I / O,您必须在最低级别(即Win32 API级别)进行重定向,并在更高级别上修复链接,具体如下:
- 通过调用
CreateFile
来分配新句柄。
- 使用
SetStdHandle
将该新句柄分配给所需的std I / O设备。
- 使用
_open_osfhandle
(返回文件描述符号码)将该新句柄与相应的C std文件描述符相关联。
- 使用上述解释的
dup2
技术重定向返回的文件描述符。
这是一个样本片段以重定向stdout
:
HANDLE new_stdout = CreateFileA("log.txt", ...);
SetStdHandle(STD_OUTPUT_HANDLE, new_stdout);
int fd = _open_osfhandle(new_stdout, O_WRONLY|O_TEXT);
dup2(fd, STDOUT_FILENO);
close(fd);
顺便说一句,如果不需要程序内进行输入/输出重定向,那么您可以使用一个小批处理文件在命令行中使用控制台的输入/输出重定向:
@echo off
start "my_gui_app" "path/to/my_gui_app.exe" 1> "path/to/log.txt"
freopen
的函数可以帮助你。 - Some programmer dudestd::cout
写入的整个缓冲区。 - Some programmer dude