【Linux】基础IO
基础文件IO
- C库的文件接口
- 系统调用的文件接口
- 文件描述符和文件流指针的关系
- 重定向
C库的文件接口
在c语言中,会使用fopen,fclose,fseek,fread,fwrite等函数进行文件IO的操作
以fopen函数举例
//FILE*表示文件流指针,path表示打开文件的路径,mode表示以什么方式打开
FILE* fopen(const char* path, const char* mode);
而我们如何去查看FILE到底是什么呢?
1.使用man手册去查看fopen在哪个头文件声明的
man fopen
(如果显示No manual entry for fopen,则需要进行man手册的安装yum install man-pages
)
2.安装完成后进入man手册,看到包含的是stdio.h文件
3.vim /usr/include/stdio.h
进入头文件
4.搜索FILE,找到了FILE,是typedef struct _IO_FILE FILE;
,说明FILE是一个结构体
5.光标移动到FILE中,按ctrl + ]进行跳转,(若无法跳转,先用ctags -R ./
建立映射关系)
6.在FILE中,fileno就是文件描述符
而打开方式分别有r, w, r+, w+, a+
等,不论哪种打开方式,都会返回一个FILE类型的文件流指针,因此我们使用时会这样调用
FILE fp = fopen("./1.txt", "r");
需要注意的是:上述的这些函数都是c库所定义的函数,由c库去维护。而当我们使用fopen去打开一个文件时,默认会打开一个文件,而这个文件就是文件描述符,文件描述符的设置次序为最小未使用
系统调用的文件接口
与c语言类似,操作系统也提供了文件IO的接口,open, close, lseek, write, read
等
以open函数举例;
// int 类型的返回值实际上就是文件描述符,pathname为创建的目标文件,flags打开文件的类型,
// 如果使用了O_CREAT,则需要传递第三个值,mode指明文件访问权限,传递一个八进制的三位数
int open(const char* pathname, int flags);
int open(const char* pathname, int flags, mode_t mode);
同样的,也会创建一个文件描述符
文件描述符和文件流指针的关系
总统来说:文件流指针包含了文件描述符,文件流指针是c库中维护的一个结构体,而文件描述符是linux内核维护的。
文件描述符:(fd_array[i]结构体指针数组的下标就是文件描述符)struct task_struct结构体中有一个struct files_struct结构体指针,指向了一个struct files_struct结构体,这个结构体中有一个struct file fd_array[i]结构体指针数组(被称为文件描述符表),这个数组内的每一个元素都是一个结构体指针struct file*,指向struct file这样一个结构体,这个结构体中描述了文件的信息(例如:文件大小,文件所有者,文件权限,文件在磁盘中的存储位置等)。
文件流指针:是在c库中定义的一个struct _IO_FILE{…}一个结构体,每个文件都有一个文件流指针,这个结构体中包含了文件的信息,同时也包含了文件描述符。
重定向
直到了文件描述符的本质,实际上重定向就是将文件描述符的对应的struct file* 指针的指向修改。
重定向的接口int dup2(int oldfd, int newfd);
是将oldfd的值,拷贝到newfd中,重定向为oldfd。
例子:将标准输出重定向到tmp.txt中
linux so cool被输出到了tmp.txt中
分析:printf是将内容打印到屏幕中,实际上就是打印到标准输出,而dup2之后,标准输出被重定向到了fd也就是文件描述符为3的位置,而3指向的是tmp.txt文件,因此屏幕没有输出,而是将内容输出到tmp.txt中。