74

我想重新打开stdinand stdout(也许stderr当我在它的时候)文件句柄,以便将来调用printf()orputchar()puts()将转到文件,并且将来调用getc()and 这样将来自文件。

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

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

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

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

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

而且,如果是这样,我怎样才能得到stdinback 的原始值?我必须将其存储在 a 中FILE *,然后再将其取回吗?

4

8 回答 8

94

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

116. 该freopen函数的主要用途是更改与标准文本流(、、或)关联的文件stderrstdin因为stdout这些标识符不需要是可修改的左值,fopen函数返回的值可以分配给这些左值。

freopen经常被误用,例如stdin = freopen("newin", "r", stdin);. 这并不比fclose(stdin); stdin = fopen("newin", "r");. 两个表达式都尝试分配给stdin,但不能保证是可分配的。

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

于 2009-02-25T15:19:38.683 回答
17

我想你正在寻找类似的东西freopen()

于 2009-02-25T05:58:57.530 回答
10

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

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

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

希望这些信息有用。

于 2009-06-03T23:21:54.740 回答
9

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

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

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

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

  • 相同的打开文件(或管道)
  • 相同的文件指针(两个文件描述符共享一个文件指针)
  • 相同的访问模式(读、写或读/写)
于 2009-02-25T06:22:58.253 回答
9
freopen("/my/newstdin", "r", stdin);
freopen("/my/newstdout", "w", stdout);
freopen("/my/newstderr", "w", stderr);

... do your stuff

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

这使我的圆钉方孔表上的针达到顶峰,您要完成什么?

编辑:

请记住,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() 的预期行为,如您所见,您仍然只使用三个文件描述符(和关联的流)。

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

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

于 2009-02-25T15:31:53.270 回答
3

freopen解决简单的部分。如果您没有阅读任何内容并且愿意使用诸如dupor之类的 POSIX 系统调用,那么保留旧的标准输入并不难dup2。如果你开始阅读它,所有的赌注都没有了。

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

我鼓励你坚持那些你愿意放弃旧的stdin并且stdout因此可以使用freopen.

于 2009-02-25T06:27:12.707 回答
3

同时,有一个 C 源代码库可以为您完成所有这些工作,重定向 stdout 或 stderr。但很酷的部分是它允许您为拦截的流分配任意数量的回调函数,然后您可以非常轻松地将单个消息发送到多个目的地、数据库、文本文件等。

最重要的是,创建外观和行为与 stdout 和 stderr 相同的新流变得很简单,您也可以将这些新流重定向到多个位置。

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

于 2012-07-21T06:39:09.353 回答
0

这是最容易获得、最方便和最有用的方法

freopen("dir","r",stdin);
于 2013-10-28T18:50:58.707 回答