1、概述node
Unix文件操做经常使用函数包括open、close、creat、lseek、dup、dup2、fcntl等,编程
其中open、creat、 fcntl函数须要包含头文件<fcntl.h>,缓存
其他几个函数须要包含头文件<unistd.h>。网络
因为在Linux操做系统 中使用man命令能够很是方便的查找函数原型及示例,这里就不帖出函数原型了,只讲一下使用时须要注意的地方。多线程
2、文件描述符app
每个在程序中打开的文件都有一个相应的文件描述符(file descriptor),Unix操做系统中的文件描述符保存在/dev/fd目录下。async
每个进程对该目录读取到的结果都不想同(视该进程正在使用的文件 数而定)。函数
若是由open函数直接读取该路径下的文件,将视为在此进程中对该文件描述符所对应的文件进行dup操做,在大多数操做系统中将忽略打开方式, 而部分操做系统要求打开方式为所涉及文件原先打开方式的子集。ui
3、Flagsspa
当使用O_APPEND方式打开文件时,每次调用write函数会在文件最后面写入新数据,调用write函数后读取当前文件偏移量 (current offset)能够很清楚的看到该值与文件最大偏移量相等。
若是使用了O_RDWR | O_APPEND方式打开文件,程序能够对该文件在任意位置实现读取操做(read),但写入操做(write)会使文件偏移量被重置,若是读取与写入混 合使用,可能会致使读取位置出现误差。
4、函数细说
4. 1 creat & open
creat函数与
open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);
等同,使用creat函数的缺陷在于若是须要在建立的同时读写该文件,须要在建立后将文件关闭,从新以读写方式open该文件,相对而言,下面的调用方式更为简单:
open(pathname, O_RDWR | O_CREAT | O_TRUNC, mode);
其中,O_TRUNC表示:若是此文件存在,并且为只读或只写成功打开,则将其长度截短为0(即会清空文件内容)
4.2 lseek
在lseek函数中,偏移量(offset)是一个长整型,可正可负。若是偏移量大于文件最大偏移量,对该位置进行写入操做,将对文件进行扩展,文件中的空洞(从原文件最大偏移量到写入位置)被填充为0,但并不占用磁盘块。
例如:
fd = creat("file.txt", S_IRWXU); lseek(fd,102400,SEEK_SET); write(fd,"abcdefg",7);
程序执行后,使用"ls -ls file.txt"命令能够看出,文件file.txt所占块数为8.
4.3 read
使用read函数时,遇到如下状况会使read函数提早返回:
5、File Sharing
5.1 说明
在进程中,一个进程所打开的全部文件描述符存放在一个table中,table中的每条记录包括文件描述符falgs(file descriptor flags)和指向文件表的指针(fils pointer)。
一个文件表包含一个文件的状态标志(file status flags),当前偏移量(offset),一个指向v-node表的指针。一个v-node表包括v-node信息,i-node信息,文件大小等。如 图1所示:
图1. Unix文件表(进程中)
在多个进程中,可能出现多个文件描述符指向同一个文件,此时如图2所示:
图2. 多个进程中同时打开同一个文件
当使用dup、dup2函数后,文件描述符将被复制,此时如图3所示:
图3. dup后多个文件描述符指向同一个file table
5.2 控制多进程对文件的访问
在进行多进程或多线程编程时,因为没法控制CPU对进程和线程的调度,若是不加以控制,可能会在任意两条程序控制语句中间出现中断,致使数据被污染。
可使用原语来保证在特定操做中数据不会被污染,使数据同步。
原语形式的文件读写函数为 pread和pwrite。
也正由于数据可能被污染的缘由,虽然dup2(file1,file2)与close(file2); fcntl(file1, F_DUPFD, file2)等价,但第一个函数不会致使数据被污染,咱们应该使用第一个函数。
5.3 文件更新
在操做系统中,向文件中写入数据每每只是暂时写入至操做系统缓存中,由操做系统控制磁盘中文 件的更新时间。使用sync、fsync、fdatasync函数能够实现磁盘中文件的实时更新。
使用sync函数时,文件表中的全部文件将被更新。
fsync函数只更新制定文件。
fdatasync函数只更新指定文件中的数据内容,而不更新相应的文件属性。
若是file status flags中O_SYNC标志被设置,程序中每次对该文件的write操做都将致使文件被更新;若是O_DSYNC被设置,程序中每次对该文件的write操做都将致使文件中的数据部分被更新。
5.4 fcntl
fcntl函数能够修改已打开文件的属性。
当使用fcntl函数获取文件状态标记(file status flags)时,因为O_RDONLY、O_WRONLY、O_RDWR标记具备排外型,没法被直接识别,须要由O_ACCMODE掩码转换后才能够被识 别。
示例代码以下:
#include <fcntl.h> int main(int argc, char *argv[]) { int val; if (argc != 2) err_quit("usage: a.out <descriptor#>"); if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0) err_sys("fcntl error for fd %d", atoi(argv[1])); switch (val & O_ACCMODE) { case O_RDONLY: printf("read only"); break; case O_WRONLY: printf("write only"); break; case O_RDWR: printf("read write"); break; default: err_dump("unknown access mode"); } if (val & O_APPEND) printf(", append"); if (val & O_NONBLOCK) printf(", nonblocking"); #if defined(O_SYNC) if (val & O_SYNC) printf(", synchronous writes"); #endif #if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) if (val & O_FSYNC) printf(", synchronous writes"); #endif putchar('\n'); exit(0); }