目录
文件基础理解:
文件是如何组成的?
对文件操作的本质是什么?
文件被打开的本质是什么:
进程和文件的调度关系解析:
文件被打开后如何被管理(文件描述符/文件描述符表)?
文件描述符表和三个默认打开的文件:
C语言操作文件:
C操作文件的接口:
C打开文件的方式:
系统接口操作文件:
使用一个整形变量传递多个标志位:
文件基础理解:
文件是如何组成的?
-
文件由两部分组成:文件的内容和文件的属性。
-
文件内容是数据,文件属性也是数据。因此,文件内部存储文件的内容数据和属性数据。
对文件操作的本质是什么?
-
对文件的操作就是对文件内容或文件属性的操作。操作文件属性可以包括更改文件权限、修改时间戳等,而操作文件内容则是读写文件中的数据。
文件被打开的本质是什么:
-
文件可以分为已经打开的文件和未被打开的文件。要操作的就是被打开的文件==加载到内存的文件。
-
打开一个文件,实际上是操作系统将文件从磁盘加载到内存的过程。这个过程需要操作系统访问磁盘,将文件的数据加载到内存中,才能进行进一步的操作。
进程和文件的调度关系解析:
-
一个进程可以打开多个文件:操作系统为每个进程维护一个文件描述符表,用来管理该进程当前打开的文件。通过这个文件描述符表,进程可以同时对多个文件进行读写操作,每个文件都有一个独立的文件描述符用于标识和管理。
-
多个进程也可以同时打开同一个文件:文件系统支持多个进程并发访问同一个文件。在这种情况下,操作系统为每个进程创建独立的文件描述符指向同一个文件。
文件被打开后如何被管理(文件描述符/文件描述符表)?
-
文件在被打开后,操作系统会为其创建一个专用的结构体,用来管理该文件的状态和相关信息。
-
进程通过文件描述符表统一管理该进程打开的文件,而文件描述符表是一个数组,数组的每个元素都是一个指向文件结构体的指针,即 struct file *fd_array[]。
-
文件描述符是一个整数,进程通过这个整数来索引文件描述符表中的文件指针。
-
当进程打开一个文件时,操作系统会在文件描述符表中分配一个空位,将新创建的文件结构体的地址存储在该位置,并将相应的文件描述符返回给进程。
文件描述符表和三个默认打开的文件:
-
进程在运行时默认会打开三个标准输入输出流文件,即 stdin(标准输入)、stdout(标准输出)和 stderr(标准错误输出)。这三个流通常分别对应于键盘输入、显示器输出和错误信息输出。
-
这三个标准流占据文件描述符表的前三个位置,即下标 0、1、2。stdin 对应文件描述符 0,stdout 对应文件描述符 1,stderr 对应文件描述符 2。
-
在 C 语言中,这三个标准流的类型都是 FILE*。FILE 类型是 C 标准库提供的一个结构体类型,用于封装文件相关的信息。
printf("stdin->fd : %d\n",stdin->_fileno); //0
printf("stdout->fd : %d\n",stdout->_fileno); //1
printf("stderr->fd : %d\n",stderr->_fileno); //2
C语言操作文件:
C操作文件的接口:
文件操作函数 | 功能 |
---|---|
fopen | 打开文件 |
fclose | 关闭文件 |
fputc | 写入一个字符 |
fgetc | 读取一个字符 |
fputs | 写入一个字符串 |
fgets | 读取一个字符串 |
fprintf | 格式化写入数据 |
fscanf | 格式化读取数据 |
fwrite | 向二进制文件写入数据 |
fread | 从二进制文件读取数据 |
fseek | 设置文件指针的位置 |
ftell | 计算当前文件指针相对于起始位置的偏移量 |
rewind | 设置文件指针到文件的起始位置 |
ferror | 判断文件操作过程中是否发生错误 |
feof | 判断文件指针是否读取到文件末尾 |
C打开文件的方式:
C 打开文件的方式有:w、w+、r、r+、a、a+。这些模式决定了文件的打开方式以及读写权限。 | |
---|---|
w | 如果文件不存在,首先创建该文件,然后再打开。如果文件已经存在,打开文件后会清空文件中的所有内容==文件大小变为零。 |
w+ | 以读写模式打开文件。在w的基础上加了写模式。 |
r | 只读模式打开文件。如果文件不存在,r 会返回错误并且不会创建文件。如果文件存在,r 允许读取文件内容,但不允许写入。 |
r+ | 以读写模式打开文件。在r的基础上加了写模式。 |
a | 以追加模式打开文件。如果文件不存在,a 会创建文件;如果文件已经存在,a 打开文件时不会清空原有内容。任何新写入的数据都会被追加到文件末尾,保持文件中的原始数据不被修改。 |
a+ | 以读写和追加模式打开文件。在a的基础上加了可以读取文件的功能。 |
FILE* fp = fopen("log.txt", "r"); //打开文件
if (fp == NULL) //判断是否成功打开
{
perror("fopen");
return 1;
}
//...文件的访问逻辑
fclose(fp); //使用完文件后关闭
系统接口操作文件:
-
打开文件只能由操作系统完成,之前的c的函数打开文件就是对系统调用的封装。
#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); //返回值:打开成功返回文件描述符,否则返回-1
//pathname: 要打开或创建的目标文件。
//flags: 打开文件时,可以传入多个参数选项,用一个或者多个常量进行“或”运算,构成flags。
//mode_t mode:在文件不存在时,如果需要创建后打开,则要使用这个参数指定文件的访问权限
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开 //这三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写
int fd = open("myfile", O_WRONLY|O_CREAT, 0644);
-
发现w的功能相当于封装了O_WRONLY|O_CREAT,所以可以推得:C打开文件的方式实际就是对系统接口常量的封装。
使用一个整形变量传递多个标志位:
-
一个整型变量有32个比特位,如果要一次传递多个标志位,就能够每次使用32位中的一位实现一个int类型最多可以传递31个标志位。
#include<stdio.h>
#define T1 1
#define T2 (1<<1)
#define T3 (1<<2)
#define T4 (1<<3)
void print(int flags) //使用一个int整形接收多个标志位
{
if(flags & T1) printf("T1\n"); //判断标志位对应位置是否为1
if(flags & T2) printf("T2\n");
if(flags & T3) printf("T3\n");
if(flags & T4) printf("T4\n");
}
int main()
{
print(T1);
print(T2);
print(T3);
print(T4);
print(T1 | T2);
return 0;
}