一、C文件接口
1.C默认会打三个输入输出流,分别是stdin,stdout,stderr,对应的文件描述符分别是1,2,3。
2.这三个流的类型都是FILE*,fopen返回值类型,文件指针;
二、接口介绍
OPEN:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int open(const char *pathname,int flags);
int open(const char *pathname,int flags,mode_t mode);
pathname: 要打开或创建的目标文件。
flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
参数:
- O_RDONLY: 只读打开
- O_WRONLY: 只写打开
- O_RDWR: 读,写打开
- (这三个常量,必须指定一个且只能指定一个 )
- O_CREAT: 若文件不存在,则创建。需要使用mode选项,来指明新文件的访问权限
- O_APPEND: 追加写
返回值:
- 成功:新打开的文件描述符
- 失败:-1
三、系统调用和库函数
库函数(C标准库中的函数):fopen fclose fread fwrite ……
系统调用接口:open close read write lseek ……
库函数和系统调用接口是上下级的关系
可以认为,f#系列的函数,都是对系统调用的封装,方便二次开发
注:fopen,fclose等f系列的库函数一般在用户操作接口中的lib中
四、文件描述符
LINUX下,一切皆文件
LINUX进程默认情况下有3个缺省打开的文件描述符,分别是标准输入0,标准输出1,标准错误2
0,1,2对应的物理设备一般是:键盘,显示器,显示器
理解:
- 进程执行open系统调用的时候,进程和文件的关系一般是一对多的关系,一个进程中可以打开多个文件。当打开文件时,操作系统在内存中创建相应的数据结构来描述目标文件,我们把它称为file结构体,表示一个已经打开的文件。为了将进程和文件联系起来,因此每个进程中都有一个*files指针,这个指针指向一个files_struct表,这个表中包含一个指针数组,数组中的每个元素都是一个指向打开文件的指针,因此文件描述符本质上就是该数组的下标,通过文件描述符就可以找到对应文件。
文件描述符的分配规则:从最小的未被使用的文件描述符开始分配
重定向:
理解:
- 当关闭标准输出时,myfile的地址将会被写在文件描述符为1的位置,而printf函数是C库中的IO函数,一般往stdout输出,而stdout底层访问文件时,找的是文件描述符为1的位置,因此此时已经是myfile的地址,所以将内容写到了myfile文件中,而没有写进显示器地址中,完成了输出重定向。
五、FILE
因为IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上访问文件都是通过fd访问的,因此C库当中的FILE结构体内部必定封装了fd
运行结果:
hello printf
hello fwrite
hello write
但如果对进程实现重定向,./hello > file,结果为:
hello write
hello printf
hello fwrite
hello printf
hello fwrite
造成结果不同的原因为:
- 首先了解缓冲方式分为三种:无缓冲,行缓冲(显示器),全缓冲(硬盘)
- ptintf和fwrite是库函数,会自带缓冲区,数据缓冲方式为行缓冲,但当重定向到文件后,缓冲方式会变为全缓冲,放在缓冲区的数据不会立即刷新,而是等待进程结束后统一刷新
- fork( )创建子进程,父子进程要发生写时拷贝,因此父进程准备刷新时,子进程也有一份同样的数据,因此产生两份数据
- write没有输出两次,表明write不带缓冲区库函数是系统调用的“上层”,是对系统调用的封装,而write没有缓冲区,但printf、fwrite有缓冲区,因此缓冲区是二次加上的,由C标准库提供
六、文件系统
权限:可读、可写、可执行、粘滞位
文件包括文件内容和文件属性
inode: 保存文件属性
- 通常情况下一个文件有一个inode
- 一个inode有一个inode号
- 文件名和inode之间有映射关系
查找文件步骤:inode号 -> inode -> 数据块 -> 数据
LINUX中操作任何文件都是在特定目录下操作,目录也是文件,所以目录里面必定包含文件名和文件名与inode号之间的映射关系
硬链接:硬链接没有独立的inode号 硬链接是文件名和inode号之间的映射关系
软链接:软链接有独立的inode号 软链接是一个独立的目标文件 软链接里面放了目标文件所在的路径和内容
注:
- 若有一个三级目录,dir dir1 dir2
- 则dir的硬链接数为3:dir和它本身inode号的映射关系 +dir和它当前目录的映射 + dir和下级目录dir1的映射
- dir1的硬链接数为3:dir1和本身inode号的映射 +dir1和它当前目录的映射 + dir1和下级目录dir2的映射
- dir2的硬链接数为2:dir2和本身inode号的映射 +dir2和当前目录的映射
文件的三个时间:
- Access 最后访问的时间
- Modify 文件内容最后修改的时间
- Change 属性最后修改的时间