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

时间:2009-12-15 16:35:48

标签: 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;
}

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

7 个答案:

答案 0 :(得分:21)

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

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

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

答案 1 :(得分:21)

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

答案 2 :(得分: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

我不确定你是否可以在别处可靠地完成任务。

确实有效的可疑代码

以下代码适用于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;
}

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

如果您使用的是具有/dev/fd文件系统的系统,则可以使用dup()创建从sprintf(buffer, "/dev/fd/%d", old_stdout)返回的文件描述符所暗示的文件名,然后使用{ {1}}具有该名称。这将比此代码中使用的赋值更可靠。

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

mprintf.c

freopen()

mprintf.h

#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);
 }

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

mprintf()

的使用示例

然后,您可以使用:

代替原始代码
#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

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


注意:

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

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

答案 3 :(得分:13)

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

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

Mike Weller在评论中建议stdout可能并不总是可写的。在这种情况下,类似的东西可能有所帮助:

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

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

答案 4 :(得分: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");

如果将stdout重定向为以#。p>开头,则这可能不起作用

答案 5 :(得分:1)

以下代码(SwapIOB)用于要存储的Testbenches stdout流,用于与预期结果文件进行比较。

背景:使用_IOB结构管理文件流,该结构存储在20个_IOB条目的数组中。这包括stdout流。 IOB存储在一个数组中。创建文件时,应用程序代码会获取该数组中元素的ptr。然后,应用程序代码将该ptr传递给OS以处理I / O调用。因此,操作系统本身不包含或依赖自己的应用程序IOB指针。

要求:运行测试平台时,应将应用程序发出的stdout消息重定向到文件。但是,在测试模块完成后,应将stdout消息重新重定向到控制台。

此例程已经过测试,目前在Windows XP / Pro系统上使用。

void SwapIOB(FILE *A, FILE *B) {

    FILE temp;

    // make a copy of IOB A (usually this is "stdout")
    memcpy(&temp, A, sizeof(struct _iobuf));

    // copy IOB B to A's location, now any output
    // sent to A is redirected thru B's IOB.
    memcpy(A, B, sizeof(struct _iobuf));

    // copy A into B, the swap is complete
    memcpy(B, &temp, sizeof(struct _iobuf));

}  // end SwapIOB;

应用程序代码使用类似于:

的SwapIOB()
FILE *fp;

fp = fopen("X", "w");

SwapIOB(stdout, fp);

printf("text to file X");

SwapIOB(stdout, fp);

fclose(fp);

printf("text to console works, again!");

答案 6 :(得分:-1)

发现这篇文章是因为我遇到了将 printf wprintf 的输出混合在一个流(标准输出)中的问题。在研究了这个主题后,我发现只要不使用 fclose(),下面的代码就会很简单。 (在gcc上测试过(Gentoo 4.8.3 p1.1,pie-0.5.9)4.8.3。)。 使用fclose导致以后对printf()的调用都失败,只有fprint继续正确地完成工作。

int fDesc; /* file descriptor */
printf("byte-oriented output\n");
/* printf sets the output as byte-oriented */
fDesc = dup(fileno(stdout));
close(stdout);
stdout = fdopen(fDesc,"w");
wprintf(L"wchar-oriented output\n");
/* wprintf sets it to wide-character compat. */
fDesc = dup(fileno(stdout));
close(stdout);
stdout = fdopen(fDesc,"w");
/* reopen for byte-oriented output */
printf("byte-oriented output\n");

将输出从shell重定向到其他文件或通过管道也可以正常工作。

$> a.out > /tmp/out ; cat /tmp/out
$> a.out | sed "s/oriented/aligned/"

顺便说一句,freopen也能正常工作。在C ++代码中它将是:

cout << "some cout text here";
stdout=freopen(NULL,"w",stdout); // NULL to reopen same file name!
wcout << L" some wchar_t-s after them"
stdout=freopen(NULL,"w",stdout); // reset the stdout again
cout << " and some couts again." << endl;