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

发布于 2024-08-14 07:37:53 字数 438 浏览 9 评论 0 原文

#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 系统调用来做到这一点?

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

I call freopen to redirect the stdout to out.txt then I print something on the file, now I want to redirect it back to the screen, but freopen("/dev/stdout", "a", stdout); doesn't work. Is there any way to do that using ANSI C or POSIX system calls?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

面犯桃花 2024-08-21 07:37:54

使用 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,也可能不适用于 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 文件系统,你可以创建使用 sprintf(buffer, "/dev/fd/%d", old_stdout)dup() 返回的文件描述符隐含的文件名,然后使用 < code>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);
 }

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

显然,您可以创建一个 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;
}

。此外,假设您使用 C99 编译器编写的所有代码,主要是因为我在第一次声明变量时需要它们,而不是在函数的开头。)


注意:

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

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

Use fdopen() and dup() as well as 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

I'm not sure whether you can do the assignment reliably elsewhere.

Dubious code that does actually work

The code below worked on Solaris 10 and MacOS X 10.6.2 - but I'm not confident that it is reliable. The structure assignment may or may not work with 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;
}

You can't say you weren't warned — this is playing with fire!

If you're on a system with the /dev/fd file system, you could create the name of the file implied by the file descriptor returned from dup() with sprintf(buffer, "/dev/fd/%d", old_stdout) and then use freopen() with that name. This would be a lot more reliable than the assignment used in this code.

The better solutions either make the code use 'fprintf(fp, ...)' everywhere, or use a cover function that allows you set your own default file pointer:

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

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

Clearly, you can create an mvprintf() and other functions as needed.

Example use of mprintf()

Then, in place of the original code, you can use:

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

(Warning: untested code - confidence level too high. Also, all code written assuming you use a C99 compiler, primarily because I declare variables when I first need them, not at the beginning of the function.)


Caution:

Note that if the original program is invoked as ./original_program > file or ./original_program | grep something (with redirected output) or is run from a cron job, then opening /dev/tty is not usually appropriate as a way to reopen standard output because the original standard output was not the terminal.

Also, note that if the redirection of standard output is used prior to forking and execing a child program and the original standard output is reinstated in the parent, then the sequence of operations is wrong. You should fork and then adjust the I/O of the child (only), without modifying the parent's I/O at all.

少女净妖师 2024-08-21 07:37:54

在 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 被重定向开始,这可能不起作用。

On Windows, you can open "CONOUT$".

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

This probably doesn't work if stdout is redirected to start with.

九歌凝 2024-08-21 07:37:54

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

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

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

该例程经过测试,目前在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!");

The following code (SwapIOB) is used in Testbenches that want to store
the stdout stream for comparison to an expected results file.

Background: File streams are managed using an _IOB structure that is stored in an array of 20 _IOB entries. This includes stdout stream. The IOBs are stored in an array. When a file is created the application code gets a ptr to an element in that array. The application code then passes that ptr to the OS for processing I/O calls. Thus, the OS does NOT itself contain or rely on its own pointers to the application's IOB.

Requirement: When running a testbench the stdout messages issued by an application should be re-directed to a file. However, after the module under test has completed then stdout messages should be re-redirected to the console.

This routine was tested and is currently used on Windows XP/Pro system.

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;

Application code uses SwapIOB() similar to:

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!");
浮华 2024-08-21 07:37:53

我想不出一种方法以跨平台的方式做到这一点,但在 GNU/Linux 系统(也许还有其他符合 POSIX 的系统)上,您可以 freopen ("/dev/tty", " a”,标准输出)。这就是你想要做的吗?

I can't think of a way to do this in a cross-platform manner, but on GNU/Linux systems (and maybe other POSIX-compliant ones, too) you can freopen ("/dev/tty", "a", stdout). Is this what you were trying to do?

比忠 2024-08-21 07:37:53

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

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

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

Unfortunately, there doesn't seem to be a good way:

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

The best recommendation is not to use freopen in this circumstance.

小嗲 2024-08-21 07:37:53

一般来说,你不能。您已关闭该文件,该文件可能是管道或其他文件。它不可重新打开。您可能已经保存了 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);

另一个编辑:如果您使用它来重定向子进程的输出,就像您在其他地方的评论所建议的那样,您可以在分叉之后重定向它。

Generally speaking, you can't. You have closed the file, which could've been pipe or whatever. It's not reopenable. You might have saved stdout value, then assign some fopen to it and then close it and copy the old value back. Example:

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

Mike Weller suggested below in comments that stdout might not always be writable. In this case something like that might help:

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

Another edit: if you're using it to redirect output from the child process like your comment elsewhere suggest, you can redirect it after the fork.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文