笔者为unix新手,写文章的目的一是总结理解自己看过的内容,以防自己不懂,二是能有幸解决各位看客的问题也是我的荣幸,文章内容有问题还请各位批评指正。
文件描述符
对于unix内核,所有打开的文件都通过文件描述符引用。可以想象为班级每个人都有一个学号,当点名某个学生时,需要喊出对应学号(即文件描述符)。另外呢,班级里面有几个“老人”,分别占用0,1,2,这三个文件描述符,他们是0:标准输入(一般指键盘输入) 1:标准输出(一般指终端显示) 2:标准错误(一般指终端显示的错误信息)。其他同学则依次使用之后的学号。
open openat函数
-
作用:打开或创建一个文件
-
格式:
int open(const char *path, int oflag, ...mode)
int openat(int fd, const char *path, int oflag, ...mode)
-
返回值: 成功返回文件描述符,失败返回-1
-
不同点:path为绝对路径时,fd参数可忽略,path为相对路径时,fd为相对路径在文件系统的开始地址
-
oflag参数:O_RDONLY(只读打开),O_WRONLY(只写打开),ORDWR(读写打开),O_EXEC(只执行打开),O_SEARCH(只搜索打开),这五个参数为有且只能有一个,其他参数可选,O_APPEND(每次写追加到文件尾),其他可选参数待了解之后再进行补充。
lseek函数
- 作用:为打开文件设置偏移量
- 格式:
off_t lseek(int fd, off_t offset, int whence)
- 返回值:若成功返回偏移量,失败返回-1
- whence参数:SEEK_SET(偏移量为距开始处offset个字节),SEEK_CUR(偏移量为当前值+offset),SEEK_END(偏移量为文件长度+offset)
read函数
- 作用:从打开文件中读数据
- 格式:
ssize_t read(int fd, void *buf, size_t nbytes)
- 返回值:若成功返回读到的字节数,若读到文件尾,则返回0,失败返回-1
write函数
- 作用:向打开文件写入数据
- 格式:
ssize_t write(int fd, const void *buf, size_t nbytes)
- 返回值:若成功返回已写的字节数,则返回0,失败返回-1
文件共享
UNIX系统支持在不同进程间共享打开文件,理解文件共享之前先说明一下内核I/O的数据结构。内核使用3种数据结构表示打开的文件:
(1)进程表项
每个进程在进程表中都有一个记录项。包含fd标志和文件指针,指针指向文件表项。
(2)文件表项
内核为所有打开的文件表维持一张文件表。包含文件状态标志(读、写、添写等),当前文件偏移量,指向v节点的指针。
(3)v节点表项
每个打开的文件都有一个v节点结构。包含文件类型和各种函数的指针,还包含i节点信息。(i节点包含文件长度、所有者、指向实际数据的指针等)
下面考虑这样一个问题,一个进程可以打开多个文件,多个进程也可以打开同一个文件,这样他们的文件表项指向同一个v节点表项,当多个进程同时读同一文件时不会有问题,而当多个进程同时写一个文件时,考虑到偏移量的存在,可能会造成相互之间进行覆盖的后果,关于这一方面的内容下一篇文章详细介绍。
另外上述进程表项的fd标志和文件表项的文件状态标志可参考这个链接。