关于IO操作

open:
    1. 几乎可以打开任何文件,无论是磁盘还是什么(linux统一文件模型的好处;
    2. 参数中打开标志的flag:
    O_RDONLY,O_WRONLY,O_RDWD这三个只必须有一个,可加这些;
    O_APPEND:标明该文件的所有写操作都会添加在文件结尾,除非显示调用lseek;
    O_CREAT: 该选项时则要第三个选项,指定新建文件的权限位,实际的权限是 mode & ~umask;
    O_TRUNC:当文件存在时,会把文件长度重置为0;
    O_NONBLOCK/O_NDELAY:非阻塞模式;
    O_SYNC:用同步IO打开.直到写到底层设备才会返回成功;
    O_ASYNC:异步信号,仅 terminate,pseudo-terminate,socket,pipe,fifo可用;

creat:
    1. 历史原因,之前open无法打开一个不存在的文件;
    2. 等价于 open(path, O_RDWR | O_CREAT | O_TRUNC, mode);

close:
    1. 关闭一个文件时,会释放所有加在该文件上的所有记录锁;
    2. 关闭一个进程时,会关闭该进程的所有打开文件.因些,很多程序利用该特性,不显示关闭文件,等进程关闭时,自动关闭打开文件;

lseek:
    1. 每个对应的文件描述符(fd)有自己的文件偏移量,通常是非负整数,但有些设备充许负的偏移量,所以返回值测试最好是比较是否等于-1;
    2. 仅将当前的文件偏移量记录在内核中,不引起任何IO操作;
    3. 文件偏移量可以大于文件长度,下一次写将加长该文件,并在文件中形成空洞,该空洞默认填充内容为0;
    4. 使用lseek时,若是手动定位到文件结尾时,与默认打开时使用的O_APPEND的效果是不同的;
    6. 使用O_APPEND后,任何写操作之前,会先把文件指针移动到结尾,读操作的时候不会,所以,无论如何设置lseek,写操作时,都会写在文件末尾;

read:
    1. 成功则返回读到的字节数,返回0,则到达文件结尾,-1时出错;
    2. read执行成功后,对应的offset也会增加实际读的字节数;
    3. read与write使用相同的offset值;

write:
    1. 每次写成功后,文件偏移量会增加实际写的字节数;
    2. write属于覆盖写,也就是说,假设偏移量:offset,写入长度:len,文件总长度:size;若offset+len < size时,写成功后,文件总长度还是size,但是offset到len这段内容发生了变化;
    若offset+len > size时,写成功后,文件总长度为offset+len,文件内容中相应也变化了;
    3. 因为write属于覆盖写,所以,同时打开多个文件时,最后的内容是最后一个写入的内容;

流程解析:
    struct task_struct {
        struct fs_struct*;
        struct files_struct*;
    };
    struct files_struct {
        stuct file **fd;
    };
    struct file {
        struct       dentry *f_dentry;            //目录项
        struct     file_operations    *f_op;        //文件操作集
        int           f_flags;                        //打开文件标志
        fmode_t       f_mode;                        //文件权限模式
        loff_t       f_pos;                        //文件偏移量
    }
    注意:fd指的是数组fd[],也就是 struct file **fd;文件描述符用fid表示;
    1.首先,每个进程自己的进程结构体task_struct中,会包含两个指针,分别是fs_struct、files_struct,其中fs_struct保存的是当前进程运行目录所在文件系统的信息;
    files_struct保存的是关于该进程打开的文件信息的指针;
    2.files_struct会有一个字段fd,该字段是一个文指针数组,包含所有已经打开的文件指针:struct file*,一般fd会默认包含三个打开文件指针,分别代表标准输入、标准输出与标准错误;
    3.struct file中包含该文件相关的目录项指针(dentry)、文件偏移量(f_pos)、打开标志(f_flags)、对应文件系统提供的操作函数指针(f_op);
    4.文件偏移量就是lseek对应的值,打开标志就是open时的O_RDWR这些值,f_op就是对应具体文件系统的open、close、write、read这些函数的指针集合(比如ext3与fat32或者其它文件系统,对于write之类的函数实现是不相同的,但是接口相同);
    5.进程调用open时,就会在字段fd这个数组中新添加一个file结构体,该文件的文件描述符用fid表示,通过fd[fid],再找到对应的文件指针struct file*;
    6.调用read、write时,会在字段fd中通过fd[fid],找到file结构体,然后,找到对应文件系统所对应的相关函数,执行到具体底层下去;
    7.调用lseek时,其实就是直接修改对应file结构体中的文件偏移量的;
    8.调用close时,会释放对应的fd中的file结构体;

注意:
    1.同一个进程可以打开同一个文件多次,且具有不同的fd,就是说在fd数组中,会有不同的file结构体;
    2.多个进程打开同一个文件时,也是对应的不同的file结构体;
    3.同一文件的不同的file结构体中目录项(dentry)指针是相同的,目录项指向的就是具体的文件的保存的物理位置(该说法不正确,但可以这样子理解),也算是殊途同归;

dup,dup2,fork:
    1. 执行dup(fid)操作后,会产生新的fid1,而fd[fid]与fd[fid1]所指向的file的指针相同,所以,它们共享相同的文件状态标志及文件偏移量;
    2. 执行dup2(fid, fid1)时,若fied1已经打开,则先关闭,然后,其它同dup(),也共享相同的file指针;
    3.fork():该操作之后,则所有父进程打开的文件描述符,子进程也复制;所以,父子进程的fd数组是两个,但对应的file指针相同,所以,文件偏移量相同.
    
限制变量:
    1.一个进程可以打开的最大文件数通过 include/linux/fs.h中的NR_OPEN值来限制,该值我的版本是1024;
    2.整个操作系统,一共可以打开的最大文件数,在内核启动时已初始化好了,对应的是 /proc/sys/fs/file-max,当然,什么时候,root都不会受该值限制;

task_struct:
    对应目录:include/linux/sched.h
struct task_struct {
    volatile long state;                //进程运行状态:/* -1 unrunnable, 0 runnable, >0 stopped */
    unsigned int policy;                //优先级

    pid_t pid;                            //进程ID号
    pid_t tgid;                            //

    struct task_struct *real_parent;    //指向创建它的进程
    struct task_struct *parent;            //指向父进程

    struct list_head children;            //指向子进程表
    struct list_head sibling;            //指向兄弟进程表
    struct task_struct *group_leader;    //指向线程组第一个线程
    struct list_head thread_group;        //指向线程组进程表

    struct thread_struct thread;        //线程相关
    struct fs_struct *fs;                //文件系统相关
    struct files_struct *files;            //打开文件相关
    struct signal_struct *signal;        //对应信号相关
    struct sighand_struct *sighand;
    ...
};

file_struct:
    对应目录: include/linux/fs.h,在2.6.23中不在这个文件内,具体在哪,没找到;
stuct files_struct {
    int max_fds;                        //文件对象当前最大数目
    int max_fdset;                        //文件描述符的最大数目
    int next_fd;                        //以分配的最大文件描述符加1
    struct file **fd;                    //指向文件对象指针数组的指针
    fd_set * close_on_exec;                //执行exec()时需要关闭的文件描述符指针
    fd_set * open_fds;                    //指向打开文件描述符的指针
    struct file *[] fd_array;            //文件对象指针的初始化数组
    ...
};

file:
    对应目录:  include/linux/fs.h
struct file {
    struct list_head    fu_list;        //用于通用文件对象的链表指针
    struct path        f_path;                //该结构中包含dentry目录项指针
    #define f_dentry    f_path.dentry    //与文件相关的目录项别名
    struct file_operations    *f_op;        //指向文件操作表的指针
    atomic_long_t        f_count;        //文件对象的引用计数器
    unsigned int        f_flags;        //打开文件时所指写的标志
    fmode_t            f_mode;                //进程的访问模式
    loff_t            f_pos;                //文件偏移量
    u64            f_version;                //版本号,每次使用后自动递增
    void            *f_security;        //指向文件对象的安全结构的指针
    void            *private_data;        //指向特定文件系统或设备驱动程序所需要的数据的指针
    ...
};

你可能感兴趣的:(linux编程,read,write,open,IO)