当前位置: 首页 > 面试题库 >

为什么在重定向到文件时stdout需要显式刷新?

终波涛
2023-03-14
问题内容

的行为printf()似乎取决于的位置stdout

  1. 如果stdout被发送到控制台,则将printf()被行缓冲并在打印换行符后刷新。
  2. 如果stdout被重定向到文件,则除非fflush()调用缓冲区,否则不会刷新缓冲区。
  3. 此外,如果printf()stdout重定向到文件之前使用过,则随后的(对文件的)写操作将被行缓冲并在换行符之后被刷新。

什么时候是stdout行缓冲的,什么时候fflush()需要调用?

每种的最小示例

void RedirectStdout2File(const char* log_path) {
    int fd = open(log_path, O_RDWR|O_APPEND|O_CREAT,S_IRWXU|S_IRWXG|S_IRWXO);
    dup2(fd,STDOUT_FILENO);
    if (fd != STDOUT_FILENO) close(fd);
}

int main_1(int argc, char* argv[]) {
    /* Case 1: stdout is line-buffered when run from console */
    printf("No redirect; printed immediately\n");
    sleep(10);
}

int main_2a(int argc, char* argv[]) {
    /* Case 2a: stdout is not line-buffered when redirected to file */
    RedirectStdout2File(argv[0]);
    printf("Will not go to file!\n");
    RedirectStdout2File("/dev/null");
}
int main_2b(int argc, char* argv[]) {
    /* Case 2b: flushing stdout does send output to file */
    RedirectStdout2File(argv[0]);
    printf("Will go to file if flushed\n");
    fflush(stdout);
    RedirectStdout2File("/dev/null");
}

int main_3(int argc, char* argv[]) {
    /* Case 3: printf before redirect; printf is line-buffered after */
    printf("Before redirect\n");
    RedirectStdout2File(argv[0]);
    printf("Does go to file!\n");
    RedirectStdout2File("/dev/null");
}

问题答案:

刷新stdout取决于其缓冲行为。可以将缓冲设置为三种模式:(_IOFBF完全缓冲:等待,直到fflush()可能),_IOLBF(行缓冲:换行符触发自动刷新)和_IONBF(始终使用直接写)。“对这些特性的支持是由实现定义的,并且可能会受到setbuf()setvbuf()功能的影响。”
[C99:7.19.3.3]

“在程序启动时,三个文本流是预先定义的,无需显式打开-
标准输入(用于读取常规输入),标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。最初打开时,标准错误流没有被完全缓冲;标准输入和标准输出流被完全缓冲,当且仅当可以确定该流不引用交互式设备时。”
[C99:7.19.3.7]

观察者行为的解释

因此,发生的事情是该实现做了特定于平台的操作,以确定是否stdout要进行行缓冲。在大多数libc实现中,该测试是在首次使用流时完成的。

  1. 行为#1很容易解释:当流用于交互式设备时,它是行缓冲的,并且printf()会自动刷新。
  2. 现在也可以想到案例2:当我们重定向到文件时,该流将被完全缓冲fflush(),除非使用,否则将不会刷新该流,除非您向其写入大量数据。
  3. 最后,对于只对基础fd执行一次检查的实现,我们也理解情况#3。因为我们在第一个中强制将stdout的缓冲区初始化,所以printf()stdout获得了行缓冲模式。当我们换掉fd进入文件时,它仍然是行缓冲的,因此数据会自动刷新。

一些实际的实现

每个libc都具有如何解释这些要求的自由度,因为C99没有指定“交互设备”是什么,POSIX的stdio条目也没有对此进行扩展(除了要求打开stderr以便读取之外)。

  1. Glibc。参见filedoalloc.c:L111。在这里,我们用于stat()测试fd是否为tty,并相应地设置缓冲模式。(这是从fileops.c中调用的。)stdout最初有一个空缓冲区,并根据fd 1的特性在第一次使用流时分配它。

  2. BSD库 非常相似,但是要遵循的代码更简洁!请在makebuf.c中查看此行



 类似资料:
  • 问题内容: 这是我的代码: 如果删除,该表不会更新。但是对于select语句,我不需要那个。我很好奇为什么? 问题答案: 在DB- API 规范要求连接到数据库开始新的事务,默认情况下。您必须确认所做的任何更改,或放弃它们。 请注意,如果数据库支持自动提交功能,则必须首先将其关闭。 纯语句,因为它们从不对数据库进行任何更改,因此不必提交更改。

  • 问题内容: 我在cyberciti.biz的评论中看到了这个有趣的问题。 我发现我什至找不到在sh的单行命令中执行此操作的灵活方法。 到目前为止,我对解决方案的想法是: 但是您会看到,这不是同步的,而且致命的是,它是如此丑陋。 欢迎与您分享这个想法。:) 问题答案: 你要 这里的顺序很重要。假设stdin(fd 0),stdout(fd 1)和stderr(fd 2)最初都连接到tty,因此 首先

  • 问题内容: 如何在Python中将stdout重定向到任意文件? 当从ssh会话中启动运行了很长时间的Python脚本(例如,Web应用程序)并进行背景调整,并且ssh会话关闭时,该应用程序将在尝试写入stdout时引发并失败。我需要找到一种方法来使应用程序和模块输出到文件而不是stdout,以防止由于而导致失败。当前,我使用将输出重定向到文件,并且可以完成工作,但是我想知道是否有一种出于好奇而无

  • 问题内容: 我正在尝试将函数的标准输出重定向到tkinter文本小部件。我遇到的问题是,它会将每一行写到一个新窗口中,而不是将所有内容都列出在一个窗口中。该函数扫描目录并列出任何0k文件。如果没有文件为0k,则将其打印出来。因此,问题在于,如果目录中有30个0k文件,它将打开30个窗口,每个窗口只有一行。现在,我知道问题出在哪里。如果您查看我的功能代码,我会告诉您: 我知道,每次os.stat看到

  • 我这里有一个非常奇怪的用例,我正试图为我的学生编写一些简单的程序,帮助他们学习python。为了让它工作,我在TKinter框架中嵌入了一个PyGame窗口,我需要重定向stdout以更改PyGame窗口中的某些内容。我有重定向工作,如果我重定向到一个文件,它的工作很好,但如果我试图改变文本,它不工作。我将一个字符串硬编码到PyGame文本更改代码中,这是可行的,但由于某些原因,它无法与重定向文本

  • 问题内容: 我可以将数据发送到服务器,但是只有在使用FromBody-Attribute时才可以。 为什么无法使用Post从主体自动读取json数据? 后端Web API 前端angularjs 问题答案: 仅因为某事是POST请求,所以没有明确的规则如何传递参数。POST请求仍可以包含URL中编码的查询参数。方法参数应该是“简单”类型(字符串,整数等)的查询参数。 通常,复杂类型应该是POST表