fopen'd文件的默认输入和输出缓冲?

时间:2010-04-19 18:46:21

标签: c file stream buffer

因此,FILE流可以同时具有输入和输出缓冲区。您可以使用setvbuf调整输出流(我不知道任何使用输入缓冲区大小和行为的方法)。

此外,默认情况下缓冲区为BUFSIZ(不确定这是POSIX还是C的东西)。很明显这对stdin / stdout / stderr意味着什么,但新打开文件的默认值是什么?它们是否针对输入和输出进行缓冲?或者只是一个?

如果它是缓冲的,输出默认为阻止或行模式吗?

编辑:我已经做了一些测试,看看Jonathan Leffler的回答如何影响现实世界的节目。看来如果你做了一个读,那么写。写入将导致输入缓冲区的未使用部分完全丢弃。事实上,将会有一些寻求将事物保持在正确的文件偏移量。我使用了这个简单的测试程序:

/* input file contains "ABCDEFGHIJKLMNOPQRSTUVWXYZ" */
#include <stdio.h>
#include <stdlib.h>

int main() {

    FILE *f = fopen("test.txt", "r+b");
    char ch;
    fread(&ch, 1, 1, f);
    fwrite("test", 4, 1, f);
    fclose(f);
    return 0;
}

导致以下系统调用:

read(3, "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", 4096) = 27 // attempt to read 4096 chars, got 27
lseek(3, -26, SEEK_CUR)                 = 1        // at this point, I've done my write already, so forget the 26 chars I never asked for and seek to where I should be if we really just read one character...
write(3, "test", 4)                     = 4        // and write my test
close(3)                                = 0

虽然这些显然是实现细节,但我发现它们非常有趣,就标准库的实现方式而言。感谢Jonathan的深刻回答。

1 个答案:

答案 0 :(得分:6)

单个文件流只有一个缓冲区。如果文件同时用于输入和输出,则必须确保在读取和写入(或写入和读取)操作之间执行适当的操作(fseek()或等效操作)。

标准频道的缓冲行为取决于平台。

通常,当输出到达终端时,stdout是行缓冲的。但是,如果stdout要转到文件或管道而不是终端,那么它通常会切换到完全缓冲。

通常,stderr是行缓冲或无缓冲的,以确保看到错误消息(例如,即使程序即将崩溃)。

通常,stdin是行缓冲的;这意味着您有机会编辑输入(退出错误等)。你很少会调整它。同样,如果输入来自文件(或管道),则行为可能不同。

新打开的文件通常会完全缓冲。如果设备是终端,则特定实现可能会将其更改为行缓冲。

你的前提 - 有两个缓冲区 - 是不正确的。


C99的第7.19.3节,它说:

  

在程序启动时,预定义了三个文本流,无需显式打开    - 标准输入(用于读取传统输入),标准输出(用于写入)   常规输出)和标准错误(用于写入诊断输出)。最初   打开后,标准错误流未完全缓冲;标准输入和标准   当且仅当可以确定流不被引用时,输出流被完全缓冲   到交互设备。

因此,正如最初所述,stderr是无缓冲的行缓冲(它没有完全缓冲)。