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; //指向特定文件系统或设备驱动程序所需要的数据的指针
...
};
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; //指向特定文件系统或设备驱动程序所需要的数据的指针
...
};