Unix 文件I/O操作
一,概要
Unix 的文件I/O操作主要指的是:打开文件、读文件、写文件等。其中常用到的函数有:open、read、write、lseek、close。这些都是Unix 提供的接口,通常都是不带缓冲的I/O。
二,文件描述符、文件表、v节点表
1,文件描述符:
当打开或创建文件时,内核会向进程返回一个文件描述符。进程会根据获取的文件操作符来对文件进行一系列的操作,包括读、写等操作,既间接通过文件描述符操作文件。
举一个例子,假如房东要将房子出租出去,委托给A、B、C中介,那现在有多个房客要看房,中介只需要和房东拿钥匙。房子就好比我们要操作的文件,钥匙就好比文件描述符,中介就好比我们的程序(进程)。如下图:
![](/attachment/201411/10/29899640_1415620711lll9.png)
那对于文件描述符是操作文件的入口,通过文件描述符,我们进而可以操作文件,如读、写等操作。
![](/attachment/201411/10/29899640_14156207664BrW.png)
每个进程表在进程表中有一个记录项,这些记录项中有一张打开的文件描述符表,每个描述符占一项,与文件描述符关联的是:文件描述符的标志、指向一个文件表项的指针。
2,文件表
内核为所有打开文件维持一张文件表,文件表项包含:文件状态标志、当前文件偏移量、指向该文件v节点表项的指针。这里文件状态标志指的是打开文件所标志的操作,如:只读、只写、读写。
3,v节点表
每个打开的文件或设备都有一个v节点结构,v节点结构包含了文件类型和对此文件进行各类操作的函数指针类型。
如下图:
![](/attachment/201411/10/29899640_1415620813kWDG.png)
三,系统提供的部分函数接口
1,open函数——打开文件
函数原型:
#include
int open(const char *pathname,int flag, .../*mode_t mode*/);
返回值:成功则返回文件描述符,失败则返回-1;
参数说明:
pathname : 打开或创建的文件名
flag : 为常量,这些常量定义在 头文件中。
值如下:
O_RDONLY 只读打开。
O_WRONLY 只写打开。
O_RDWR 读写,打开。
O_APPEND 每次写都追加到文件尾部。
O_CREAT 如文件不存在,则创建它。如果此项存在,则第三项参数mode则为文件权限。
O_EXCL 如果同时存在指定的O_CREAT,且文件存在,则会出错。这里常用于测试文件是否存在;如果不存在,则创建此文件,这使得测试和创建成为原子操作。
O_TRUNC 如果文件存在,而且为只写或只读成功打开,则将其长度截短为0。
O_NOCTTY 如果pathname指的是终端设备,则不将该设备分配为此进程的控制终端。
O_NONBLOCK 如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选项为文本的本次打开操作盒后续的I/O操作设置非阻塞模式。
O_DSYNC 使每次write等待物理I/O操作完成,但如果写操作并不影响读取刚写入的数据,则不等待文件属性被更新。
O_RSYNC 使每个文件描述符作为参数read操作等待,直至任何对文件同一部分进行的未决写操作完成。
O_SYNC 使每次write都等到物理I/O操作完成,包括write操作引起的文件属性更新所需的I/O。
2,creat 函数——创建文件
函数原型:
#include
int creat(const char * pathname,mode_t mode)
返回值:成功则返回为只写打开的文件描述符,出错则返回-1;
参数:
pathname : 创建的文件名
mode:模板
creat函数缺点是以只写的方式打开所创建的文件,如果需要写完文件后,读取文件的内容,则必须先creat文件,close文件,在open文件,最后read文件。而现在open函数也具有该功能:
open(pathname,O_RDWR|O_CREAT|O_TRUNC,mode);
3,close函数——关闭打开的文件
函数原型:
#include
int close(int filedes);
返回值:0(成功),-1(失败);
参数:fildedes 文件描述符
4,lseek函数——定位文件偏移量
函数原型:
#include
off_t lseek(int filedes,off_t offset,int whence)
返回值:成功返回新的文件偏移量,出错返回-1;
参数:
filedes:文件描述符
offset:于whence相关联,
whence=SEEK_SET,则将该文件的偏移量设置为距文件开始处offset个字节;
whence=SEEK_CUR,则将该文件的偏移量设置为其当前值加offset,offset可为正负;
whence=SEEK_END,则将该文件的偏移量设置为文件长度加offset,offset可为正负;
5,read函数——读入文件内容
原型:
#include
ssize_t read(int filedes,void * buf,size_t nbytes)
返回值:成功返回读取到的字节数,若到达文件尾返回0,出错返回-1;
参数:
filedes:文件描述符
buf:存放读取的数据
nbytes:读取的字节数
6,write函数——写入文件
原型:
#include
ssize_t write(int filedes,const void * buf,size_t nbytes);
返回值:成功则返回已写的字节数,出错返回-1;
参数:
filedes:文件描述符
buf:写入文件的数据
nbytes:写入文件的字节数
7,dup、dup2——复制文件描述符
原型:
#include
int dup(int filedes);
返回值:成功返回新的文件描述符,出错 -1;
参数:
filedes:需要复制的文件描述符;
int dup2(int filedes,int filedes2);
返回值:成功返回新的文件描述符,出错 -1;
参数:
filedes:需要复制的文件描述符;
filedes2:指定返回文件描述符的值,如果指定的这个值已经打开,则将其关闭;
8,sync、fsync、fdatasync——保证磁盘实际的文件内容与高速缓冲区的内容一致
原型:
#include
int fsync(int filedes);
描述:只针对所描述的filedes指定的文件起作用,并同步更新文件的属性,且在等待写入磁盘后操作结束然后返回;
返回值:成功返回0,出错返回-1
参数:filedes 设定的同步的文件描述符
int fdatasync(int filedes)
描述:同fsync类似,只是fsync同步更新文件的属性,fdatasync只针对数据;
返回值:成功返回0,出错返回-1
参数:filedes 设定的同步的文件描述符
void sync(void);
描述:将所有修改过的块缓冲区排入写队列然后返回,它并不等待实际写磁盘操作结束
四,总结
Unix对于文件IO的操作,系统为维持三张表:进程表项、文件表、v节点表。在进程表项中打开或获取一个文件描述符,此文件描述符在内核中拥有一个文件表,此文件表保存的是文件状态标志、当前文件偏移量、v节点指针。而对于v节点表则主要存储文件的v节点信息、i节点信息等。
阅读(569) | 评论(0) | 转发(0) |