一般打开并读取一个文件,传统方法就是两个系统调用:
int open (const char ‘*path‘, int ‘oflag‘, .../*,mode_t ‘mode‘ */); ssize_t read(int fd, void *buf, size_t count);
这里 read 有一个 buf 缓冲区,这个是由你的应用程序控制的,在你的应用程序虚拟内存地址空间中,究竟是 堆,还是栈,这个看你声明 buf 时候是怎么做的。
不过,内核中,也会有一个缓冲区,这个你的应用程序是看不见的,当你读取时,内核会将数据放入自己的缓冲区,然后 copy 到用户态你程序的缓冲区中。这个东西,在内核叫做 buffer cache,由IO 子系统管理,对于 Unix 系统来说,一般会预留最多 10% 作为 buffer cache 使用。
如果你使用的是 mmap 方法,则会有:
void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
这一套过程与上面的 open/read 不同,是由内核分页子系统管理的,说白了,就是用虚拟内存调页的方式,将文件直接 map 到程序的地址空间中,这个 map 也是靠内核实现的,这东西叫做 page cache,你也知道虚拟内存限制少很多,可以 map 直到占用全部内存。
传统 read/write buffer cache 有个问题,就是一旦固定后,大小没法调节,这样分配多了就是浪费,分配少了就会造成很多的上下文切换做 copy 而且这个东西与分页系统割裂。所以后来就出现了 Unified Buffer Cache,统一用 Page Cache 解决以上问题。
对于使用C语言标准IO函数,将文件抽象为 流 的概念,当打开一个流时,返回指向FILE对象的指针。该对象通常是一个结构,包括用于实际IO的文件描述符,指向用于该流缓冲区的指针,缓冲区的长度,当前在缓冲区的字符数和出错标志。
参考链接:
https://www.zhihu.com/question/30868347/answer/49751213
从文件 I/O 看 Linux 的虚拟文件系统
http://www.ibm.com/developerworks/cn/linux/l-cn-vfs/index.html
http://www.ibm.com/developerworks/cn/linux/l-cache/