如何在freopen("out.txt","a",stdout)之后将输出重定向回屏幕

Hof*_*ann 29 c posix stdout

#include <stdio.h>

int main() {
    printf("This goes to screen\n");
    freopen("out.txt", "a", stdout);
    printf("This goes to out.txt");
    freopen("/dev/stdout", "a", stdout);
    printf("This should go to screen too, but doesn't\n");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我调用freopen将stdout重定向到out.txt然后我在文件上打印一些东西,现在我想将它重定向回屏幕,但是freopen("/ dev/stdout","a",stdout); 不起作用.有没有办法使用ANSI C或POSIX系统调用?

Pat*_*ski 22

我想不出以跨平台的方式做到这一点的方法,但是在GNU/Linux系统上(也可能是其他符合POSIX标准的系统),你可以freopen ("/dev/tty", "a", stdout).这是你想要做的吗?

  • 这将在重定向或管道连接到另一个进程时中断. (10认同)
  • 霍夫曼当然对你的具体情况来说可能已经足够好了,所以我把这些评论放在那些会发现问题的人身上,并且当整个事情被重定向或完全没有tty时可能会关心这个案例. (4认同)

And*_*est 21

不幸的是,似乎没有一个好方法:

http://c-faq.com/stdio/undofreopen.html

最好的建议是不要在这种情况下使用freopen.


Jon*_*ler 14

使用fdopen()dup()以及freopen().

int old_stdout = dup(1);  // Preserve original file descriptor for stdout.

FILE *fp1 = freopen("out.txt", "w", stdout);  // Open new stdout

...write to stdout...   // Use new stdout

FILE *fp2 = fdopen(old_stdout, "w");   // Open old stdout as a stream

...Now, how to get stdout to refer to fp2?
...Under glibc, I believe you can use:

fclose(stdout);    // Equivalent to fclose(fp1);
stdout = fp2;      // Assign fp2 to stdout
// *stdout = *fp2;   // Works on Solaris and MacOS X, might work elsewhere.

close(old_stdout);   // Close the file descriptor so pipes work sanely
Run Code Online (Sandbox Code Playgroud)

我不确定你是否可以在其他地方可靠地完成任务.

实际工作的可疑代码

下面的代码适用于Solaris 10和MacOS X 10.6.2 - 但我不确定它是否可靠.结构赋值可能适用于Linux glibc,也可能不适用.

#include <stdio.h>
#include <unistd.h>

int main(void)
{
    printf("This goes to screen\n");
    int old_stdout = dup(1);  // Consider dup(STDOUT_FILENO) or dup(fileno(stdout))
    FILE *fp1 = freopen("out.txt", "a", stdout);
    printf("This goes to out.txt\n");
    fclose(stdout);
    FILE *fp2 = fdopen(old_stdout, "w");
    *stdout = *fp2;                       // Unreliable!
    printf("This should go to screen too, but doesn't\n");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

你不能说你没有被警告 - 这就是玩火!

如果您使用的是具有/dev/fd文件系统的系统,则可以创建由dup()with 返回的文件描述符隐含的文件名sprintf(buffer, "/dev/fd/%d", old_stdout),然后使用freopen()该名称.这将比此代码中使用的赋值更可靠.

更好的解决方案是使代码在任何地方使用'fprintf(fp,...)',或使用允许您设置自己的默认文件指针的覆盖函数:

mprintf.c

#include "mprintf.h"
#include <stdarg.h>

static FILE *default_fp = 0;

void set_default_stream(FILE *fp)
{
    default_fp = fp;
}

int mprintf(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);

    if (default_fp == 0)
        default_fp = stdout;

    int rv = vfprintf(default_fp, fmt, args);

    va_end(args);
    return(rv);
 }
Run Code Online (Sandbox Code Playgroud)

mprintf.h

#ifndef MPRINTF_H_INCLUDED
#define MPRINTF_H_INCLUDED

#include <stdio.h>

extern void set_default_stream(FILE *fp);
extern int  mprintf(const char *fmt, ...);

#endif
Run Code Online (Sandbox Code Playgroud)

显然,您可以根据需要创建mvprintf()和其他函数.

mprintf()的使用示例

然后,您可以使用以下代码替换原始代码:

#include "mprintf.h"

int main()
{
    mprintf("This goes to screen\n");
    FILE *fp1 = fopen("out.txt", "w");
    set_default_stream(fp1);
    mprintf("This goes to out.txt\n");
    fclose(fp1);
    set_default_stream(stdout);
    mprintf("This should go to screen too, but doesn't\n");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

(警告:未经测试的代码 - 置信度太高.此外,假设您使用C99编译器编写的所有代码,主要是因为我在第一次需要它时声明变量,而不是在函数的开头.)


警告:

请注意,如果原始程序被调用为./original_program > file./original_program | grep something(具有重定向输出)或从cron作业运行,则打开/dev/tty通常不适合作为重新打开标准输出的方法,因为原始标准输出不是终端.

另请注意,如果在分叉和执行子程序之前使用标准输出的重定向并且在父级中恢复原始标准输出,则操作序列是错误的.您应该分叉然后调整子进程的I/O(仅限),而不必修改父进程的I/O.


Mic*_*ker 13

一般来说,你不能.你已经关闭了文件,这可能是管道或其他什么.它不可重新开启.您可能已保存stdout值,然后为其分配一些fopen然后关闭它并将旧值复制回来.例:

FILE *o = stdout;
stdout=fopen("/tmp/crap.txt","a");
printf("Oh no!\n");
fclose(stdout);
stdout = o;
Run Code Online (Sandbox Code Playgroud)

Mike Weller在评论中建议stdout可能并不总是可写的.在这种情况下,这样的事情可能有所帮助

int o = dup(fileno(stdout));
freopen("/tmp/crap.txt","a",stdout);
printf("Oh no!\n");
dup2(o,fileno(stdout));
close(o);
Run Code Online (Sandbox Code Playgroud)

另一个编辑:如果您使用它来重定向子进程的输出,就像其他人建议的注释一样,您可以在fork之后重定向它.


use*_*751 5

在Windows上,您可以打开"CONOUT $".

freopen("test.txt", "w", stdout);
printf("this goes to test.txt");
freopen("CONOUT$", "w", stdout);
printf("this goes to the console\n");
Run Code Online (Sandbox Code Playgroud)

如果将stdout重定向到开头,这可能不起作用.

  • 你的解决方案不允许我恢复stderr.[关于_dup的这篇文章](http://msdn.microsoft.com/en-us/library/8syseb29.aspx)适合我. (2认同)