文件IO学习笔记第二章:打开文件

      大家好,我是小智!

fopen函数

      想要对文件进行读写访问的前提是必须先打开文件,标准IO中提供了一个函数叫做fopen(),用户只需要包含标准输入输出头文件 #include <stdio.h> 即可调用。

image

      fopen函数是有返回值的,如果文件打开成功,则返回值返回指向该文件的文件流指针,如果文件打开失败,则返回值为NULL。

image

思考

问题一

  • fopen函数的返回值是一个指向被打开文件的FILE类型的指针,请问FILE类型是什么?

      回答:FILE类型其实是一个结构体数据类型,它包含了标准 I/O 库函数为管理文件所需要的所有信息,比如包括用于实际I/O 的文件描述符、指向文件缓冲区的指针、缓冲区的长度、当前缓冲区中的字节数以及出错标志等。头文件stdio.h中有关于FILE类型的相关描述,如:

image

问题二

  • 可以看到FILE类型其实就是一个结构体,结构体类型名称为struct _IO_FILE,但是经过查找之后发现头文件stdio.h中并没有关于该结构体的定义,那这个结构体中到底都有哪些成员?

      回答:阅读stdio.h中的条件编译选项可以发现在stdio.h中还包含了另一个头文件<libio.h>,这个头文件中才有关于FILE结构体类型的定义,该头文件的路径同样在Linux系统的/user/include目录下。

image

      打开头文件<libio.h>之后,可以找到关于FILE结构体类型的定义,可以发现FILE结构体类型中的成员数量很多

image

      可以看到FILE结构体类型中有一个成员是FILE类型的指针变量chain,该指针可以指向下一个被打开文件的文件信息区,也就是可以把FILE类型当做数据结构中的链表的结点,结点中除了可以存储数据域之外,还可以利用指针域存储下一个结点的地址。

      简单理解:用户可以在一个程序中利用fopen函数打开多个文件,每次打开一个文件,内核就会从堆内存中申请一块FILE结构体大小的空间用来存储文件的所有信息,然后按照文件打开的顺序把每个打开的文件的结构体形成一条链表,然后使用链表头进行管理。

      注意:打开文件的目的无非就是对文件进行读写操作,所以每次当程序运行的时候已经有三个文件流被打开,分别是标准输入stdin、标准输出stdout、标准出错stderr,这三者在stdio.h中也是FILE指针。

image

所以内核在管理被打开文件的时候,链表中已经有三个结点存在,然后再把新节点头插入到链表中。

image

问题三

  • 请问为什么内核在为文件流申请内存的时候是申请的堆内存?请问有什么具体依据?

image

      注意:使用标准IO的时候,是不可以反复关闭相同的文件,因为释放已经被释放的堆内存,会导致段错误!!

posted @ 2025-05-16 11:00  努力赚钱的小智  阅读(31)  评论(0)    收藏  举报