文件理解
对于文件我们需要理解以下关键信息。
(1).首先我们需要了解到,只有进程可以对文件进行各种操作。
(2).对于文件来说,我们需要先打开文件,将文件加载到内存中。
而操作系统则需要对内存中的文件进行描述,存在一个file的结构体,同时在pcb中存在一个file指针,指向一个file数组,对文件进行管理。
文件相关函数
与文件相关的函数有很多,如fopen,fclose,open,close,write等等
其中open,close,write,dup2都是系统调用函数。
而fopen,fclose等等函数都是C语言的库函数,都分装了系统调用函数。这样就可以多次使用,同时可移植性高,安全性高。
open函数的3个参数,第一个是在某个路径下要创建的文件。第二个是标记,标记存在许多宏,O_CREAT,O_APPEND,O_RDONLY,O_WRONLY,这些宏都是通过位图判断的。第三个参数是文件的默认权限,返回值是fd。
关于文件描述符的理解
进程会打开文件,那么进程也需要对该进程打开的文件进行描述和管理。
进程中会维护一个指针,指向数组,数组内的元素分别都是一个file指针,而数组的下标就是文件描述符。
没打开一个文件,就会生成一个文件描述符,该文件描述符一定是文件描述数组中最小的未使用的描述符。
0号描述符是stdin。
1号描述符是stdout。
3号描述符是stderr。
文件描述符重定向
每个文件描述符表示了一个文件,对于scanf,printf等函数本质都是往stdin,stdout中写入。
而输出重定向就是将原本写入要stdout文件内的内容写入其他文件内,输出重定向也是如此。
本质就是使用dup2函数将打开的文件将stdin或stdout的文件指针交换,在写入到in out的fd中,这样就达到了重定向的效果。
FILE文件结构体
FILE结构体是C语言封装的描述文件的结构体,在C语言层面的文件函数封装了系统调用函数,而一个进程要访问一个文件,都需要使用文件描述符(fd),所以FILE结构体内一定封装了fd,并且FILE结构体内还存在文件缓冲区。
在使用C语言层面的文件接口时,都是以文件缓冲区为中介的,如print,fwrite等函数。
当进程结束后,系统都会刷新文件缓冲区,缓冲区输出到显示器中是行缓冲,输出到普通文件中则是全缓冲。
输出到显示器中,是行缓冲,遇到\n就刷新缓冲区。
输出到普通文件中,是全缓冲,此时fork了两个进程两个进程都结束,会刷新缓冲区两次,导致C库函数被打印了两遍。
如上可以看出,系统调用函数只输出了一次,这表明write函数没有缓冲区。
printf fwrite 库函数会自带缓冲区,而 write 系统调用没有带缓冲区。另外,我们这里所说的缓冲区,
都是用户级缓冲区。其实为了提升整机性能,OS也会提供相关内核级缓冲区,不过不再我们讨论范围之内。
为什么要存在缓冲区
如果没有缓冲区,则用户写入一些数据就调用系统调用,这样会极大增加时间开销,若存在缓冲区,则可以一次将多个数据写入缓冲区中在一次性调用系统调用,这样就减少了时间开销。