作者hth9494 (hth9494)
看板C_and_CPP
标题[问题] 档案I/O缓冲区请益
时间Sun May 28 04:05:24 2017
开发平台(Platform): (Ex: Win10, Linux, ...)
Linux 3.16.0-4-586
编译器(Ex: GCC, clang, VC++...)+目标环境(跟开发平台不同的话需列出)
GCC
--
在叙述问题前,我想先说下到目前为止,我对档案I/O方面理解到的一点东西。
理解不深,若有误希望大家可以指正我,或给我一点线索,谢谢T_T。
以下的理解是建立在linux环境之下。
--
一、
C语言的文件读写函式,像是fgets, fread, fputc...等,是透过一个
FILE *类型的参数来操作,而最终这些函式会呼叫诸如read或write之类
的system call,完成文件读写。
二、
一个程式被load进记忆体时,内核会有一个PCB来记录这个程式的
相关资讯,其中也会记录这个程式所开启的文件。代表着这些文件的是一些
整数,read或write也是用这些整数来当作参数,对相应的文件进行处理。
一个程式一开始会开启三个文件,分别是stdin,stdout和stderr,对应
的整数分别是0,1,2。
FILE结构内_fileno的值其实就是这个整数的值。
三、
system call的I/O是 "unbuffered I/O"。
C函式库的I/O是 "buffered I/O"。
假设我有支C如下
#include <stdio.h>
int main(void)
{
char str[20] = "Hello A.txt\n";
FILE *fpA = fopen("A.txt", "w");
fputs(str, fpA);
fclose(fpA);
return 0;
}
因为我调用了C函式fopen,所以C会帮我管理一块专属於A.txt的buffer,
关於buffer的资讯会记在fpA所指的FILE结构中。
buffer位於这支程式的记忆体空间内,在user space里。
fputs的作用就是把str写到这个user space的buffer中。
也就是说,其实执行完fputs时,str还没真正被写入A.txt,只在buffer而已。
(这是C的buffered I/O)
在kernel space里,也有一个A.txt的buffer。
write的作用就是把user space的buffer资料写到kernel space的buffer里,
之後再写回A.txt中。
(这是system call的unbuffered I/O,但我不知道为什麽叫unbuffered)
四、
如果资料被放在space buffer中且没有做flush的动作,那资料就不会
被写到文件里。
例如这个C程式就会印不出字串
#include <stdio.h>
int main(void)
{
printf("Hello world"); //不会显示在终端上
while (1);
return 0;
}
下面几种行为会导致buffer flush
1、呼叫fflush
2、fclose
3、exit
--
以上是目前为止我对文件I/O的理解。
如果有错希望大家可以教我一下,因为下面我要问的问题是建立在这
之上,结果搞不好其实我上面就错的一蹋糊涂了。
--
一、
上面说到,因为我调用了C函式来操作I/O,所以C会帮我管理一个user space
的buffer,那麽,当我不用C标准函式库,而直接使用system call来处理
文件的话,是不是就没有那个 user space buffer了?
还有,那kernel space的buffer依然存在吗?
例如这样
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(void)
{
char str[20] = "Hello A.txt\n";
int fdA = open("A.txt", O_WRONLY|O_CREAT, 0666);
write(fdA, str, strlen(str));
close(fdA);
return 0;
}
二、
一个程式开始前会先开启stdin、stdout和stderr三个文件,那很多个程式
同时执行时,kernel space buffer是怎麽运作的?
例如有三个process,p1开启这三个文件,p2、p3亦然,他们的user space各有
这三个文件的buffer,但是在kernel space中呢?也是各有三个buffer吗?
读写的时候不会冲突吗?
三、
当一个程式呼叫exit结束时,会关闭文件流并且flush user space的缓冲区,
请问kernel space的缓冲区会跟着被清空吗?
四、
以下程式码
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
char buf[10];
int n;
n = read(STDIN_FILENO, buf, 10);
if (n < 0) {
perror("read STDIN_FILENO");
exit(1);
}
write(STDOUT_FILENO, buf, n);
return 0;
}
编译成a.out并执行,结果是这样
$ ./a.out
hello world
hello worl$ d
-bash: d: command not found
我能理解当我输入hello world时,缓冲区内会有11个字元,而这支a.out只读了
10个,所以缓冲区会剩一个d,但我不明白的是,为什麽a.out结束,返回shell後
shell还会读到这个d,shell 和 a.out的缓冲区应该是分开的不是吗? 而且a.out
结束後,也应该会清空缓冲区才对,我整个黑人问号,希望大家可以跟我解释一下
这个现象,谢谢。
--
以下是我参考的资料,问题也是阅读这些资料时蹦出来的。
http://docs.huihoo.com/c/linux-c-programming/ch28s04.html
http://blog.csdn.net/astrotycoon/article/details/44993197
问题有点多,如果有那里觉得表达不清楚请跟我说下,我会再做补充。
总之感激不尽,谢谢大家T_T。
--
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 114.42.93.120
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1495915530.A.B3A.html
1F:→ tinlans: 把 APUE 拿来读一遍就行了 06/05 03:36
2F:推 galic: 补充一下,C的三个i/o stream和各自的buffer行为 规格书是 06/06 04:16
3F:→ galic: 有订的 06/06 04:16
4F:→ galic: 然後你说得kernel buffer…建议先理解unix-like对於file的 06/06 04:16
5F:→ galic: 概念不是这麽单纯 像是block和character device的定义等等 06/06 04:16