从C重新路由stdin和stdout

我想重新打开stdinstdout (也许是stderr而我在它)文件句柄,以便将来调用printf()putchar()puts()将去到一个文件,以后调用getc()这将来自一个文件。

1)我不想永久失去标准的input/输出/错误。 我可能希望稍后在程序中重用它们。

2)我不想打开新的文件句柄,因为这些文件句柄将不得不围绕很多或全局(不寒而栗)传递。

3)我不想使用任何open()fork()或其他系统相关的函数,如果我不能帮助它。

所以基本上,这是否工作:

 stdin = fopen("newin", "r"); 

而且,如果是这样,我怎样才能得到stdin的原始价值? 我是否必须将它存储在FILE * ,稍后再回来?

为什么使用freopen() ? C89规范在<stdio.h>部分的尾注之一中有答案:

116. freopen函数的主要用途是更改与标准文本stream( stderrstdinstdout )相关联的文件,因为这些标识符不需要是可以被赋值fopen函数返回的值的可修改的左值。

freopen通常被滥用,例如stdin = freopen("newin", "r", stdin); 。 这不比fclose(stdin); stdin = fopen("newin", "r"); fclose(stdin); stdin = fopen("newin", "r"); 。 这两个expression式试图分配给stdin ,这不保证是可分配的。

使用freopen的正确方法是省略赋值: freopen("newin", "r", stdin);

我想你正在寻找像freopen()

os函数dup2()应该提供你所需要的 (如果没有引用你所需要的)。

更具体地说,您可以将stdin文件描述符dup2()复制到另一个文件描述符,使用stdin执行其他操作,然后在需要时将其复制回来。

dup()函数复制一个打开的文件描述符。 具体而言,它使用F_DUPFD常量命令值为fcntl()函数提供的服务提供备用接口,其第三个参数为0。 重复的文件描述符与原始文件共享任何locking。

成功时,dup()返回一个新的文件描述符,它与原始文件具有以下相同之处:

  • 同一个打开的文件(或pipe道)
  • 相同的文件指针(两个文件描述符共享一个文件指针)
  • 相同的访问模式(读取,写入或读取/写入)
 freopen("/my/newstdin", "r", stdin); freopen("/my/newstdout", "w", stdout); freopen("/my/newstderr", "w", stderr); ... do your stuff freopen("/dev/stdin", "r", stdin); ... ... 

这是在我的圆形方孔O型米高的针头,你想完成什么?

编辑:

请记住,对于每个新创build的进程,stdin,stdout和stderr都是文件描述符0,1和2。 freopen()应该保持相同的fd,只是给它们分配新的stream。

所以,确保实际上做你想做的事情的一个好方法是:

 printf("Stdout is descriptor %d\n", fileno(stdout)); freopen("/tmp/newstdout", "w", stdout); printf("Stdout is now /tmp/newstdout and hopefully still fd %d\n", fileno(stdout)); freopen("/dev/stdout", "w", stdout); printf("Now we put it back, hopefully its still fd %d\n", fileno(stdout)); 

我相信这是freopen()的预期行为,正如你所看到的,你仍然只使用三个文件描述符(和相关的stream)。

这将覆盖任何shellredirect,因为shell不会redirect。 但是,它可能会打破pipe道。 如果你的程序发现自己在一个pipe道的阻塞端(不是FIFO,pipe道),你可能想要确保为SIGPIPE设置一个处理程序。

所以,./your_program –stdout /tmp/stdout.txt –stderr /tmp/stderr.txt应该用freopen()方便地完成,并保持相同的实际文件描述符。 我不明白的是为什么一旦改变它们就需要把它们放回去? 当然,如果有人通过了这两个选项,他们会希望它一直持续到程序结束为止。

这是Tim Post方法的修改版本; 我用/ dev / tty而不是/ dev / stdout。 我不知道为什么它不适用于标准输出(这是一个链接到/ proc / self / fd / 1):

 freopen("log.txt","w",stdout); ... ... freopen("/dev/tty","w",stdout); 

通过使用/ dev / tty,输出被redirect到应用程序启动的terminal。

希望这个信息是有用的。

freopen解决了简单的部分。 如果您没有阅读任何内容,并且愿意使用像dupdup2这样的POSIX系统调用,那么保留旧的stdin并不难。 如果你开始阅读,所有的投注都closures了。

也许你可以告诉我们发生这个问题的背景吗?

我鼓励你坚持的情况下,你愿意放弃旧的stdinstdout ,因此可以使用freopen

与此同时,还有一个C源代码库将为您执行所有这些redirectstdout或stderr。 但最酷的部分是,它可以让你分配尽可能多的callback函数,你想拦截的stream,允许你很容易地发送一个单一的消息到多个目的地,数据库,文本文件等

最重要的是,创build与标准输出和标准错误行为相同的新stream是很简单的,也可以将这些新streamredirect到多个位置。

在* oogle上查找U-Streams C库。

这是最好的方式和有用的方式

 freopen("dir","r",stdin);