Linux基础内容(13)—— 进程控制https://blog.csdn.net/m0_63488627/article/details/127932919
目录
1.文件的基本知识
1.空文件在磁盘也占空间
2.文件包括其属性和内容
3.找到一个文件是通过路径+文件名找到的
4.没有指明文件路径,默认在当前路径找文件
5.文件没有被打开时是不被执行的,我们要调用文件是通过进程帮助我们执行文件的
6.文件没有被打开是不能被直接访问的
7.用户命令进程,进程调用系统给的文件连接接口,操作系统帮助我们打开文件
8.不是所有文件都被打开的,操作系统管理用到哪些就打开哪些
9.文件操作的本质是 进程和被打开文件的关系
2.不同软件的文件操作
对于每个语言,都有对应的文件操作。这样文件操作就变的非常花样,但是如果每个软件都在Linux的操作系统中,我们要知道软件和操作系统之间存在系统调用接口以确保用户不能对操作系统内部进行非法操作,这正是因为这个单一的调用接口,其实我们就知道,无论哪个语言都需要调用系统接口来实现上层的语法。固然不同语言的文件操作不一样,但是操作系统下一视同仁,只要我们使用操作系统调用接口,那么语法就是唯一的。
1.C语言的文件操作
FILE* fp =fopen(FILE_NAME,"r");
//r,w,r+(读写,不存在报错),w+(读写,不存在创建),a(追加),a+(读写,追加打入)
1.写操作
FILE* fp =fopen(FILE_NAME,"w"); if(fp==NULL) { perror("fopen"); return 1; } int cnt = 5; while(cnt) { fprintf(fp,"%s:%d\n","hello bit",cnt--); } fclose(fp);
2.读操作
FILE* fp =fopen(FILE_NAME,"r"); if(fp==NULL) { perror("fopen"); return 1; } char buffer[64]; while(fgets(buffer,sizeof (buffer)-1,fp)!=NULL) { puts(buffer); } fclose(fp);
2.系统调用接口
打开
pathname:路径,默认当前路径
mode:文件的权限;如果打开的文件不存在,新建文件需要确定文件的权限
flags:操作指令
O_RDONLY:只读
O_WRONLY:只写
O_RDWR:读写
O_CREAT:创建
O_TRUNC:清空
O_APPEND:追加
为了了解这个指令的原理,得先讲清楚一些东西:首先这个flags传入的都是类似一堆大写加_的形式,我们能猜想到这个数其实是宏定义的标记。一个操作需要表示,用一个整型也可以用一个位也可以,那么为了节省空间,我们使用一个位表示这个操作是否使用。
关闭
状况分析
1.若文件操作只读,但是没有文件存在,则报错,说明没有文件。需要加O_CREAT自己创造
2.操作文件需要调节文件的权限,即O_CREAT后要对mode进行定义,不然生成的文件是乱码,这是错误的操作
3.正确操作为下图
4.出现文件权限问题就是需要对其设置,那么我们就会有掩码指令
比较之前,我们的文件确实权限变成预期的。不过这里说明,我们改变的掩码是子进程的掩码,也就是生成文件的这个进程,但是shell进程的umask没有变化。
写操作
fd:文件返回值
buf:写入的数据
count:数据的大小
区别于C语言的接口,C语言的w指令直接创造文件,定制文件的权限,再次输入清空文件;但是对于系统调用来说,其实这些都是不同的位指令,故系统调用时,需要用到写指令,创建指令和文件权限,清空文件指令。若是追加,则不选择清空文件指令,选择追加指令。
读操作
fd:文件返回值
buf:读取接受的数据
count:读取数据的大小
返回值为得到数据的大小
3.文件的相关概念
1.一个进程能打开多个文件
2.既然是打开的文件就是操作系统需要管理的数据
3.操作系统遵循先描述后组织,将文件描述成struct_file的结构体,里面存放文件的属性
首先我们为了为了后续的知识,我们需要操作铺垫:进程开辟多个文件操作进行对文件的管理
得到的结果如下:
为什么操作系统对文件的描述是通过数字描述的呢?而且为什么我们开创的第一个文件就是从3开始的呢?
这个文件的描述是数字,并且为连续的数字,很难不联系到数组,那么我们也能大概了解,其实这个文件的描述是一组数组,数组里找到文件,文件反馈的下标是对应的数字。 由此我们能得到下面的结论。
4.在上面操作系统的写和读操作都有一个int类型的fd,这个东西是文件描述符,用于指定文件的
5.既然文件描述符是描述文件的,但是C语言对文件的描述是FILE* 是一个结构体类型,那么必然C语言封装了对应的文件描述符
其实C语言中有stdin,stdout,stderr三个输入输出流对应的其实是键盘,显示器,显示器被操作系统管理的文件(一切皆文件思想),那么我们能猜测012被这三个占了。
打印三个结构体中的文件描述符,果然如猜想的一样。
文件描述符的具体知识
1.打开文件意味着在磁盘的文件被拷贝到内存中
2.拷贝下来的文件是需要管理的,此时的struct_file变成一串结构体链连接方便管理
3.面对海量的打开文件,其实一个进程不会全部都拿到,太多也不是好事,需要什么拿什么
4.既然如此那么在进程的PBC中存着描述文件的结构体指针,即为struct file_struct*file
5.该结构体指针指向结构体file_struct,这个结构体是进程管理自己打开的文件的数据结构
6.该结构体里有一个指针数组,用于存储struct_file的地址,秉承着用什么拿什么的原则,该数组就是在一群的文件连接中拿出自己要的存到数组里,某个下标就代表这个操作系统管理的指定文件
文件描述符的分配规则
1.打开文件时,系统会将磁盘中复制到内存中,并且被操作系统管理
2.管理时,进程会得到指定打开文件的结构体指针,将其放入文件描述符表
3.文件描述符表的下标指向指定文件
4.文件被放入描述符表的原则为,放在最小空位处
特别的,将1号对应的stdout关闭,文件将失去输出的能力,我们将看不到输出的值反馈在shell中。
重定向:
注意上面关闭stdout的操作,其实就是将文件描述符表去除掉stdout的地址,但是我们又将新建的文件fd放入到下标1的位置处。那么1号指向了新打开的文件,printf是将stdout中打印的,但是stdout被替换成了新文件。所以会被打印到新文件之中。该行为被称为重定向。 不过上面的代码不会在文件中得到打印数据,因为文件刷新策略和显示器刷新策略不同,所以我们需要刷新缓冲区。那么我们知道其实printf是将数据打印到1号下标的文件之中,只是默认文件为stdout所以打印在显示器中。
重定向本质:上层fd不变,底层对应的文件结构体变了。
系统的重定向接口:
dup2:两个文件符之间的拷贝,一个文件描述符的内容拷贝到另一个文件描绘符中。
old拷贝到new中,最后剩下old,new被取代
Linux重定向:
> :输出 ,本来输出到显示器的数据加载到文件中
>>:追加,追加到文件末尾
// int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666); 输出重定向 // int fd = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666); 追加重定向 // dup2(fd, 1);
<:输入
//int fd = open("log.txt", O_RDONLY); 输入重定向 //dup2(fd, 0);
4. Linux下一切皆文件
1.硬件不能与操作系统直接交互
2.通过所谓驱动实现交互,驱动对硬件进行数据结构化,使得其拥有可以被调用的属性
3.这些所谓的读写方式互不相同,因为每一个硬件的应用方式不一样
4.操作系统在管理文件时需要对文件进行描述,描述其大小,指向有多少,读写方式等
5.对于操作系统而言,不会直接调用驱动的函数,因为太杂了。所以它描述了一个函数指针,文件被管理时,该文件中的读写函数指向驱动层的读写方式,此时达到统一
6.在用户看来我们只是调用了所谓操作系统封装好的,一样的,访问读写指令,所以Linux下一切皆文件
7.补充一点,对于不同硬件接收的读写信号不一样,实现的功能不一样,其实就是C++中多态的思想,只不过实现是用C语言实现的。
8.对不同的文件操作,在我们看来是对文件进行关闭,其实不然,因为文件被很多进程打开,只是我们当下进程进行的将fd的文件描述符表的地址关闭,对于操作系统中,其实就是文件的结构中指向使用进程减一
9.因为硬件都被操作系统管理了,说明在操作系统中有结构体就是描述所谓文件的代码