从C转发stdin和stdout

时间:2009-02-25 05:55:46

标签: c redirect stdio

我想重新打开stdinstdout(可能是stderr,而我正在使用它)文件句柄,以便将来调用printf()或{{1或putchar()将转到某个文件,以后对puts()的调用将来自文件。

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

2)我不想打开新的文件句柄,因为这些文件句柄必须要经过大量传递或全局传递(不寒而栗)。

3)如果我无法帮助,我不想使用任何getc()open()或其他与系统相关的功能。

基本上,这样做是否有效:

fork()

而且,如果确实如此,我怎样才能获得stdin = fopen("newin", "r"); 的原始值?我是否必须将其存储在stdin中并稍后再取回?

8 个答案:

答案 0 :(得分:78)

为什么要使用freopen()? C89规范在<stdio.h>

部分的尾注之一中有答案
  

116。 freopen 功能的主要用途是更改与标准相关联的文件   文字流( stderr ,    stdin stdout ),因为这些标识符无需   值可修改的左值   由 fopen 函数返回   可以被分配。

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

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

答案 1 :(得分:15)

我认为你正在寻找像freopen()

这样的东西

答案 2 :(得分:10)

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

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

通过使用/ dev / tty,输出被重定向到启动应用程序的终端。

希望此信息有用。

答案 3 :(得分:9)

os函数dup2()应该提供你需要的东西(如果没有提到你需要的东西)。

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

  

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

     

成功时,dup()返回一个新的文件描述符,该描述符与原始文件具有以下共同点:

     
      
  • 相同的打开文件(或管道)
  •   
  • 相同的文件指针(两个文件描述符共享一个文件指针)
  •   
  • 相同的访问模式(读,写或读/写)
  •   

答案 4 :(得分:9)

freopen("/my/newstdin", "r", stdin);
freopen("/my/newstdout", "w", stdout);
freopen("/my/newstderr", "w", stderr);

... do your stuff

freopen("/dev/stdin", "r", stdin);
...
...

这针在我的圆钉方孔o表上,你想要完成什么?

修改

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

因此,确保实际执行您希望的操作的好方法是:

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()的预期行为,正如您所看到的,您仍然只使用三个文件描述符(和相关的流)。

这将覆盖任何shell重定向,因为shell没有任何重定向。然而,它可能会打破管道。您可能希望确保为SIGPIPE设置处理程序,以防程序发现自己位于管道的阻塞端(而不是FIFO,管道)。

因此,./your_program --stdout /tmp/stdout.txt --stderr /tmp/stderr.txt应该可以使用freopen()轻松完成,并保持相同的实际文件描述符。我不明白为什么你一旦改变它们就需要把它们放回去?当然,如果有人通过了任何一个选项,他们会希望它一直持续到程序终止?

答案 5 :(得分:3)

freopen解决了简单的问题。如果您没有阅读任何内容,并且您愿意使用POSIX系统调用dupdup2,那么保持旧的stdin并不难。如果你开始阅读它,所有的赌注都会被取消。

也许您可以告诉我们出现此问题的背景?

我建议您坚持放弃旧stdinstdout的情况,因此可以使用freopen

答案 6 :(得分:3)

与此同时,有一个C源代码库可以为您完成所有这些,重定向stdout或stderr。但很酷的部分是,它允许您根据需要为截获的流分配尽可能多的回调函数,这样您就可以非常轻松地将单个消息发送到多个目标,数据库,文本文件等。

最重要的是,创建看起来和行为与stdout和stderr相同的新流变得微不足道,您可以将这些新流重定向到多个位置。

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

答案 7 :(得分:0)

这是最方便实用的方式

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