首页 > 代码库 > 第3章 文件I/O(3)_内核数据结构、原子操作

第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;
}

第3章 文件I/O(3)_内核数据结构、原子操作