1回顾 在C语言中 标准库IO接口都有什么?
打开文件 : fopen(r/r+/w/w+/a/a+/)
关闭文件 : fclose
函数 fopen 打开文件名为 path 指向的字符串的文件,将一个流与它关联。
参数 mode 指向一个字符串,以下列序列之一开始 (序列之后可以有附加的字符):
r 打开文本文件,用于读。流被定位于文件的开始。
r+ 打开文本文件,用于读写。流被定位于文件的开始。
w 将文件长度截断为零,或者创建文本文件,用于写。流被定位于文件的开始。
w+ 打开文件,用于读写。如果文件不存在就创建它,否则将截断它。流被定位于文件的开始。
a 打开文件,用于追加 (在文件尾写)。如果文件不存在就创建它。流被定位于文件的末尾。
a+ 打开文件,用于追加 (在文件尾写)。如果文件不存在就创建它。读文件的初始位置是文件的开始,但是输出总是被追加到文件的末尾。
2 系统提供的IO 接口都有什么?
打开文件: open函数
int open(const char *pathname, int flags);
读文件 : read
read - 在文件描述符上执行读操作
概述
ssize_t read(int fd, void *buf, size_t count);
描述
read() 从文件描述符 fd 中读取 count 字节的数据并放入从 buf 开始的缓冲区中.
如果 count 为零,read()返回0,不执行其他任何操作. 如果 count 大于SSIZE_MAX,那么结果将不可预料.
写文件 :write
write -在一个文件描述符上执行写操作
概述
ssize_t write(int fd, const void *buf, size_t count);
描述
write 向文件描述符 fd 所引用的文件中写入 从 buf 开始的缓冲区中 count 字节的数据. POSIX规定,当使用了write()之后再使用 read(),那么读取到的应该是更新后的数据.
关闭文件描述符
int close(int fd);
3 库函数和系统调用的关系
结论: 库函数是对系统调用接口的一层封装,库函数与系统调用接口是上下级的调用关系,我们在上层调用库函数执行IO操作,最终是通过系统调用接口实现的.
fopen函数调用open函数。
4 什么是文件描述符
结论: 文件描述符就是 pcb 中fd_array[struct file] 的下标,它是该文件的操作句柄.
我们知道在Linux下,一切皆文件,当我们要打开一个应用程序时就相当于打开了一个文件,程序启动以后,相当于生成了一个进程,要打开文件就要最终通过系统调用接口open函数 。于是进程和文件之间产生了关联 。
我们的文件存储在磁盘中, 当我们要打开一个文件时,要操作系统会对该文件进行管理,管理的方式是: 先描述,再组织. 首先操作系统会对该文件进行描述(文件大小,文件地址,等等),描述完之后,将文件的描述信息 放在内存中的file_struct结构体中.这个结构体中存储了各个要打开文件的描述信息。 在进程中有一张表,这个表中有一个结构体指针数组。 我们每通过进程打开一个文件,操作系统就会 用一个struct file去描述符它,然后会将描述这个文件的结构体地址放进在这个结构体数组中,同时会给它一个号码(占个坑给个号码),这个号码就是文件描述符,它就是该指针数组的一个下标,他就是该文件的操作句柄,进程对该文件的所有操作都是通过这个下标实现的,进程先找到结构体指针数组,然后通过下标找到该文件的描述信息,通过描述信息找到对应的文件,进而对文件进行操作。
5 文件描述符和文件指针的关系
文件指针是对文件描述符的一层封装,是上下级调用关系.
文件指针是在C标准库中,它是库函数层面的操作句柄
文件描述符是在系统调用接口中,它是系统调用层面的关系
在表面上,我们通过文件指针操作文件,而实质上我们还是文件指针还是在底层通过文件描述符来实现对一个文件的操作.
6 文件描述符的分配规则
规则: 最小未使用规则
Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2
0,1,2对应的物理设备一般是:键盘,显示器,显示器
7 重定向
概念:
这里说的重定向指的是文件描述符的重定向,当文件描述符这个下标所指代的文件描述信息发生变化时(变成另外一个文件的描述信息),此时文件描述符没有变,而文件描述符所指代的文件已经发生了变化此时若继续对该文件描述符进行操作,此时操作的就是另外一个文件。
本质: 改变了数据的流向。
举个例子:
现在我们要调用库函数printf 执行打印操作 printf(“hello world”) ;
printf 是库函数,我们调用printf ,在本质上是先 stdout 标准输出文件 中写入数据" hello world" 现在我们 用 close 接口关闭标准输出文件 close(1) ,此时该文件描述符变为未使用状态, 现在我们打开另外一个文件 tset.txt 操作系统恰好将 1 这个文件描述符分配给test.txt 文件 ,此时我们再来指向printf函数 ,由于printf函数对应的文件描述符仍然是 1 ,此时我们对文件描述符 1 进行操作实际上是对文件 test.txt 进程操作, 此时我们将 “hello world” 写入到了test.txt 中