c - 只读模式下的 fopen() 及其缓冲区

标签 c io stream buffer

考虑以下 C 语言代码,尽管非常困惑:

#include<stdio.h>

int main() {
    char buf[3]; //a new, small buffer
    FILE *fp = fopen("test.txt", "r"); //our test file, with the contents "123abc"
    setvbuf(fp, buf, _IOFBF, 2); //we assign our small buffer as fp's buffer \
                                 //in fully buffered mode
    char character = fgetc(fp); // get the first character...
    character = fgetc(fp);      // and the next...
    character = fgetc(fp);      // and the next... (third character, '3')
    buf[2] = '\0'; //add a terminating line for display
    fputs(buf, stderr); //write our buffer to stderr, should show up immediately
}

编译并运行代码将打印“3a”作为我们自行指定的缓冲区 buf 的内容。我的问题是:这个缓冲区是如何填满的?调用 fgetc() 是否意味着多次调用直到缓冲区已满然后停止(我们只调用了三个 fgetc,这不应该包括现在'a')?第一个缓冲区是“12”,这是否意味着当另一个 fgetc() 调用被调用并且指针引用缓冲区范围之外的内容时,缓冲区是被清除然后填充下一个数据 block ,还是被简单地覆盖?我知道缓冲区大小取决于平台,所以我更关心一般情况下,读取模式下的 fopen()ed 流如何将字符拉入其缓冲区。

最佳答案

缓冲区,以及填充的具体方式和时间,是 stdio 包中的一个实现细节。但它可能的实现方式是fgetc 从缓冲区中获取一个字符,如果缓冲区中有字符可用的话。如果缓冲区为空,它会通过(在您的情况下)从文件中读取另外两个字符来填充缓冲区。

因此,您的第一个 fgetc 将从文件中读取 12 并将其放入缓冲区,然后返回 '1'。你的第二个 fgetc 不会从文件中读取,因为缓冲区中有一个字符可用,并返回 '2'。你的第三个fgetc会发现缓冲区是空的,所以它会从文件中读取3a放入缓冲区,然后返回'3'。因此,当您打印缓冲区的内容时,它将是3a

请注意,这里有两个级别的“阅读”。首先,您有 fgetc 调用,然后,在该级别之下,stdio packade 中的代码正在从文件中读取。如果我们假设这是在 Unix 或 Linux 系统上,则第二种类型的读取是使用系统调用 read(2) 完成的。

较低级别的读取会立即填满整个缓冲区,因此您不需要像调用 fgetc 那样多次调用 read。 (这就是拥有缓冲区的全部意义所在。)

关于c - 只读模式下的 fopen() 及其缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23338218/

相关文章:

c++ - 如何使用 fgets 获取文本并保存 std::string

java - 当流未明确关闭时,Files.list(Path dir) 中的资源泄漏?

c - 以原子方式更改文件的属性

c - 将 stdout 和 stderr 从 fork 进程复制到文件

c - 如何调用nasm中调用c标准库的c函数?

C 缓冲区下溢定义和相关风险

python - 将输入文件的一行中的每个字符添加到列表中,并将每个列表添加到每行之后的另一个列表中

io - 试图重铸 $*ARGFILES

c++ - 输出流中的函数调用优先级

c++ - 将标准输出重定向到 ostream