我在《Unix环境高级编程》中读到过这样的内容:
行缓冲有两个注意事项。首先,标准 I/O 库用于收集每行的缓冲区大小是固定的,因此如果我们在写入换行符之前填充此缓冲区,则可能会发生 I/O。其次,每当通过标准 I/O 库从 (a) 无缓冲流或 (b) 行缓冲流(需要从内核请求数据)请求输入时,所有行缓冲输出流都会被刷新。 (b) 上限定符的原因是请求的数据可能已经在缓冲区中,这不需要从内核读取数据。显然,任何来自无缓冲流的输入(项目 (a))都需要从内核获取数据。
https://www.gnu.org/software/libc/manual/html_node/Flushing-Buffers.html指出:
刷新缓冲流上的输出意味着将所有累积的字符传输到文件。在许多情况下,流上的缓冲输出会自动刷新:
当您尝试进行输出并且输出缓冲区已满时。
当流关闭时。请参阅关闭流。
当程序通过调用 exit 终止时。请参阅正常终止。当写入换行符时(如果流是行缓冲的)。
每当任何流上的输入操作实际上从其文件读取数据时。
所以我编写了一个程序来测试这个:
#include <stdio.h>
#include <unistd.h>
int
main()
{
printf("Hello");
FILE *fp = fopen("hugefile", "r");
if (fp == NULL) {
fprintf(stderr, "Cannot open file\n");
return -1;
}
setvbuf(fp, NULL, _IONBF, 0);
sleep(2);
char buf[10];
while (fread(buf, sizeof(char), 10, fp) == 10) {
}
if (ferror(fp)) {
fprintf(stderr, "Read error\n");
return -1;
}; // I expect "Hello" to appear on a screen but it doesn't
fclose(fp);
sleep(50);
}
但 fread() 不会触发输出闪烁。我是不是漏掉了什么?
我不知道这里可能与什么相关但我使用:
gcc 版本 14.2.1 20240910
glibc 2.40+r16+gaa533d58ff-2
我认为刷新缓冲区并不意味着它会被打印到屏幕上或者任何标准输出被重定向到的地方。
通过读取标准输入来刷新标准输出:
您可以在 buf.c 中实现以下行为:
运行它:
“Hello”字符串打印到 stdout 并且不以换行符结尾)(\n),因此它不会在 2 秒后刷新,但它会在
fread()
运行时刷新。如果删除它,它将仅在最后一次睡眠后刷新。每当任何流上的输入操作实际上从其文件读取数据时。
通过读取文件刷新到文件:
重现每当任何流上的输入操作实际上从其文件读取数据时。我认为这是你的主要目标:
像这样运行它,我将得到一个仅包含当前日期的小文件,并在后台运行一个二进制文件,以便我能够看到它打印的所有消息并能够同时检查文件的内容:
如您所见,只有在运行
add more characters to FILE
后才将行添加到FILE中。fread()