第3章 文件I/O(3)_内核数据结构、原子操作
3. 文件I/O的内核数据结构
(1) 内核数据结构表
|
数据结构 |
主要成员 |
|
文件描述符表 |
①文件描述符标志 ②文件表项指针 |
|
文件表项 |
①文件状态标志(读、写、追加、同步和非阻塞等状态标志) ②当前文件偏移量 ③i节点表项指针 ④引用计数器 |
|
i节点 |
①文件类型和对该文件的操作函数指针 ②当前文件长度 ③文件所有者 ④文件所在设备、文件访问权限 ⑤指向文件数据在磁盘块上所在位置的指针等。 |
(2)3张表的关系

4. 文件的原子操作
(1)文件追加
①打开文件时使用O_APPEND标志,进程对文件偏移量调整和数据追加成为原子操作。相当于write函数将以下3个操作作为一个原子操作,不可被打断。
A.从i节点读取文件长度作为当前偏移量
B.往文件中写入数据
C.修改i节点中文件长度信息等
②内核每次对文件写之前,都将进程的当前偏移量设置为该文件的尾端。这样不再需要lseek来调整偏移量。
(2)文件创建
对open函数的O_CREAT和O_EXCL的使用,而该文件存,open将失败,否则创建该文件,并且使得文件是否存在的判定和创建过程成为原子操作。
【编程实验】原子操作
//file_append.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> //exit
#include <string.h> //strlen
#include <fcntl.h> //O_WRONLY
//为了演示文件定位与追加数据是否被打断,需要打开该程序的两个进程,分别按
//文件的格式在命令行中输入相应的参数。
int main(int argc, char* argv[]){
if( argc < 3){
printf("usage: %s content destfile\n", argv[0]);
exit(1);
}
//注意,Linux默认下文件锁是建议锁(具体见后面“文件锁”方面的内容),所以
//尽管加了O_WRONLY,但不同进程仍然可以同时修改这个文件)
//int fd = open(argv[2], O_WRONLY); //这种方式的定位与追加不是原子操作的
int fd = open(argv[2], O_WRONLY | O_APPEND); //定位与追加是原子操作
if(fd < 0){
perror("open error");
exit(1);
}
//定位到文件尾部(只使用O_WRONLY选项时,需手动定位到文件末尾
//lseek(fd, 0L, SEEK_END);
sleep(10); //为了把定位与写入过程隔开,以便演示多进程同时写入同一文件
//时会出现后启动进程格覆盖之前进程写过的内容。
//往文件尾部追加内容
size_t size = strlen(argv[1])*sizeof(char);
if(write(fd, argv[1], size)!=size){
perror("write error");
exit(1);
}
close(fd);
return 0;
}

浙公网安备 33010602011771号