fopen 文件的默认输入和输出缓冲?
因此 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
虽然这些是明显的实现细节,但我发现它们对于如何实现标准库非常有趣。感谢乔纳森的富有洞察力的回答。
So a FILE stream can have both input and output buffers. You can adjust the output stream using setvbuf
(I am unaware of any method to play with the input buffer size and behavior).
Also, by default the buffer is BUFSIZ
(not sure if this is a POSIX or C thing). It is very clear what this means for stdin
/stdout
/stderr
, but what are the defaults for newly opened files? Are they buffered for both input and output? Or perhaps just one?
If it is buffered, does output default to block or line mode?
EDIT: I've done some tests to see how Jonathan Leffler's answer affected real world programs. It seems that if you do a read then a write. The write will cause the unused portion of the input buffer to dropped entirely. In fact, the there will be some seeks that are done to keep things at the right file offsets. I used this simple test program:
/* 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;
}
resulted in the following system calls:
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
While these are clearly implementation details I found them to be very interesting as far as how the standard library could be implemented. Thanks Jonathan for your insightful answer.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
单个文件流具有单个缓冲区。如果文件同时用于输入和输出,则必须确保在读取和写入(或写入和读取)操作之间执行适当的操作(fseek() 或等效操作)。
标准通道的缓冲行为取决于平台。
通常,当输出到达终端时,stdout 是行缓冲的。但是,如果 stdout 要发送到文件或管道而不是终端,它通常会切换到完全缓冲。
通常,stderr 要么是行缓冲的,要么是无缓冲的,以确保错误消息能够被看到(例如,即使程序即将崩溃)。
通常,stdin 是行缓冲的;这意味着您有机会编辑输入(错误时退格等)。你很少会调整这个。同样,如果输入来自文件(或管道),则行为可能会有所不同。
新打开的文件通常会被完全缓冲。如果设备是终端,则特定的实现可能会将其更改为行缓冲。
您的前提 - 有两个缓冲区 - 是不正确的。
C99 第 7.19.3 节说:
因此,正如最初所述,stderr 要么是无缓冲的,要么是行缓冲的(它不是完全缓冲的)。
A single file stream has a single buffer. If the file is used for both input and output, then you have to ensure that you do appropriate operations (fseek() or equivalents) between the read and write (or write and read) operations.
The buffering behaviour of the standard channels is platform dependent.
Typically, stdout is line buffered when the output goes to the terminal. However, if stdout is going to a file or pipe rather than to a terminal, it most usually switches to full buffering.
Typically, stderr is either line buffered or unbuffered, to ensure that error messages get seen (for example, even if the program is about to crash).
Typically, stdin is line buffered; this means you get a chance to edit your input (backspacing over errors, etc). You would seldom adjust this. Again, if the input is coming from a file (or pipe), the behaviour might be different.
Newly opened files will generally be fully buffered. A particular implementation might change that to line buffering if the device is a terminal.
Your premise - that there are two buffers - is incorrect.
Section 7.19.3 of C99, it says:
So, as originally stated, stderr is either unbuffered or line buffered (it is not fully buffered).