注:文章的所有内容均出自《Linux/UNIX 系统编程手册》一书,文章的内容在于将书中的一些重要知识点提取出来并加以自己的理解,形成一个类型提纲的东西,方便查阅和复习。
0、open函数flag参数解析
a、读写权限:O_RDONLY O_WRONLY O_RDWR
b、打开存在并有内容的文件时:O_APPEND、O_TRUNC:O_TRUNC属性去打开文件时,如果这个文件中本来是有内容的,则原来的内容会被丢弃;O_APPEND属性去打开文件时,如果这个文件中本来是有内容的,则新写入的内容会接续到原来内容的后面。
c、同时指定 O_EXCL 与 O_CREAT 作为 open() 的标志位时,如果要打开的文件已然存在,则 open() 将返回一个错误。
d、O_NONBLOCK:以非阻塞的方式打开文件。
e、O_SYNC:write阻塞等待底层完成写入(同步到硬盘)才返回到应用层。
1.原子操作的重要性
举两个例子:
以独占方式创建一个文件
同时指定 O_EXCL 与 O_CREAT 作为 open() 的标志位时,如果要打开的文件已然存在,则 open() 将返回一个错误。这提供了一种机制,保证进程是打开文件的创建者。对文件是否存在的检查和创建文件属于同一原子操作。
向文件尾部追加数据
考虑如下代码:
if(lseek(fd,0,SEEK_END)==-1)
errExit("lseek");
if(write(fd,buf,len)!=len)
fatal("Partial/failed write");
若多个进程执行此操作,可能出现数据覆盖的现象,为了防止此现象的发生,需要将文件偏移量的移动与数据写操作纳入同一原子操作。在打开文件时加入 O_APPEND 标志就可以保证这一点。
2.文件控制操作 fcntl()
fcntl() 的用途是获取,修改或添加 open 打开文件的 flag 标志或访问模式。
获取与判断:
int flags,accessMode;
flags = fcntl(fd,F_GETFL);
if(flags=-1)
errExit("fcntl");
在上述代码之后,可以以如下代码测试文件是否以同步写方式打开:
if(flags & O_SYNC)
printf("writes are synchronized\n")
判定访问模式,需使用掩码 O_ACCMODE 与 flag 相与:
accessMode = flags & O_ACCMODE;
if(accessMode == O_WRONLY || accessMode == O_RDWR )
printf("file is writable\n");
更改
调用 fcntl() 函数的 F_SETFL 命令,使用 |= 添加状态标志:
int flags;
flags =fcntl(fd,F_GETFL);
if(flags == -1)
errExit("fcntl");
flags |= O_APPEND;
if(fcntl(fd,F_SETFL,flags)==-1)
errExit("fcntl");
3.文件描述符、文件句柄和inode之间的关系
- 每个进程对应一个文件描述符表,每一个文件描述符表包含了文件描述符fd0到fd?,进程每次打开一个文件,都会为文件分配一个文件描述符
- 打开文件表每一项对应一个句柄,句柄包含了文件偏移量和状态标志(flag参数),文件访问模式(mode参数)等信息
- i-node表的每一项对应到一个具体的文件,包括文件类型和文件锁等信息
可能出现以下几种情况:
a.同一进程的不同文件描述符可以指向同一句柄:例如通过调用dup()或fcntl()。
b.不同进程的同一文件描述符可以指向同一句柄:通过fork()调用。
c.不同文件句柄可以指向相同的i-node:两个进程对同一文件发起了open调用。
4.复制文件描述符
newfd=dup(1); //返回值为3,因为0,1,2已占用,创建1的副本
dup2(1,2); //创建1的副本,返回值为2
newfd=fcntl(oldfd,f_DUPFD,startfd); //为oldfd创建副本,使用大于等于startfd的编号
5.在文件特定偏移量处读写:pread和pwrite
ssize_t pread(int fd,void *buf,size_t count,off_t offset); //count为写入大小,offset表偏移
ssize_t pwrite(...)
- 需要注意的是这两个函数并不会改变文件的当前偏移量,read和write调用会改变。
6.截断文件:truncate和ftruncate
int truncate(const char *pathname,off_t length); //pathname为文件路径
int ftruncate(int fd,off_t length); //fd为文件描述符
7.创建临时文件:mkstemp和tmpfile
示例程序:
int fd;
char template[]="tmp/someXXXXXX"; //必须以6个X结尾
fd = mkstemp(template);
if(fd == -1)
errExit("mkstemp");
unlink(template); //删除临时文件
8.标准输入输出
第三列为POSIX名称,用于write,read等系统调用。
第四列为stdio流名称,用于fwrite,fread等stdio库函数。
9.lseek函数调节文件偏移量
off_t lseek(int fd,off_t offset,int whence);
whence参数解释:
SEEK_SET
将文件偏移量设置为从文件头部起始点开始的 offset 个字节。
SEEK_CUR
相对于当前文件偏移量,将文件偏移量调整 offset 个字节。
SEEK_END
将文件偏移量设置为起始于文件尾部的 offset 个字节。