【Linux】进程与文件系统(上)

由于这部分的知识很多很多,分成两回 

目录

1.文件描述符 

文件描述符


1.文件描述符 

首先我们看一下几个小问题

1.你真的理解文件原理和操作了吗?

这不是语言的问题,而是操作系统的问题

2.是不是只有C/C++有文件操作?

其他语言python,Java,go...也有文件操作,但是他们的文件操作方法不一样

那如何理解这个现象?有没有统一的角度看待所有语言的文件操作?

理解要学完本文,当然是有统一角度——操作系统角度(看完本文,你自然理解这个问题)

3.操作文件的时候第一件事情都是打开文件,打开文件是在做什么?如何理解?

本文的重点内容

4.文件=内容+属性,针对文件的操作时对内容的操作还是对属性的操作?

对内容+属性的操作

5.文件没被操作时,文件一般在什么位置?磁盘

6.当我们操作文件时,文件需要在哪里?

内存(为什么?因为冯诺依曼体系告诉我们的)

7.当我们对文件操作,文件需要被提前加载到内存,被加载的到底是内容还是属性?

至少要有属性

8.是不是只有你一个人在load?

不是,内存中一定有大量不同的文件属性

9.打开文件的本质:

将需要的文件属性加载到内存,OS内部一定会同时存在大量被打开的文件,那么操作系统要不要管理这些被打开的 文件?

当然,先构建在内存中的文件结构体 struct XXX{} 被打开的文件属性被load到文件结构体中

a.每一个被打开的文件都需要在OS内部对应的文件对象的struct结构体,可以将所有的结构体(其实这种结构体叫struct file)用某种数据结构连接起来,在OS内部,对被打开的文件进行管理 就 转换成对链表的增删查改

上面一段话简而言之:

被打开的文件,OS要为其创建对应的内核数据结构——struct file

struct file

{

//文件的各种属性

//各个file结构体之间的链接关系

}

10.文件其实可以分成两类:磁盘文件,被打开的文件(内存文件)

11.文件被打开,是谁在打开?

OS

是谁让OS打开?用户(进程为代表的)

12.我们之前所有的文件操作都是进程和被打开文件的关系

也就是struct task_struct 和struct file的关系


复习一下C语言的文件操作:

  • 打开文件的方式

w:默认写方式打开,文件不存在则新建,如果只打开文件内容自动被清空,每次写入都会从最开始写

a:不会清空文件,而是每次从文件尾追加(也就是append)

  • 复习几个C库函数

查三号手册 得

 参数列表里面的...是可变参数列表,即参数酌情写

printf //默认向显示器打印

fprintf //

sprintf //向字符串打印

snprintf //和sprintf函数不同的是,他会限制写入str字符串的字符数量为size

 1 #include <stdio.h>
  2 
  3 #define LOG "log.txt"
  4 int main()
  5 {
  6   const char * msg="hello wrt";
  7   printf("%s\n",msg);
  8   FILE * fp=fopen(LOG,"w");
  9   fprintf(fp,"%s",msg);
 10   char buf1[124]={0};
 11   sprintf(buf1,"%s",msg);
 12   printf("%s\n",buf1);                                                                                                
 13   char buf2[124];
 14   snprintf(buf2,4,"%s",msg);
 15   printf("%s\n",buf2);
 16   return 0;
 17 }

结果是 

很奇怪最后这怎么就三个字符输出

并且最后一次我们以为写入4个字符,但是只有 size - 1 个字符被写入缓冲区,最后一个字符为字符串结尾的空字符 \0


  • fgets() 

fegts函数把文件流内容写入到字符串s

这个函数遇到EOF(文件末)或者\n , 或者读到size-1个字符就停止读取

会自动在size个字符处填上\0

如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。

如果发生错误,返回一个空指针

  • fputs()

 把字符串s写入到文件流

该函数返回一个非负值,如果发生错误则返回 EOF(也就是0)

  • fread 


刚才我们在语言方面简单看了一下对文件的一些基本操作函数,现在看几个操作系统层面的系统调用

  • open

该函数的返回值是被打开文件的文件描述符

浅浅看一下flags是什么

手册里还有更多,真的是头都大了

其实这些大写的flags都是宏,他是OS让用户给自己传递的标志位

表面上他看起来是整数,有32位bit,我们可以用一个bit表示一个标志位,所以一个int最多可以传递32个标志位

简单看一下这个原理

我定义了三个宏,他们在十六进制下二进制位刚好是错开的

重点体会这种位图可以传递信息的思想 

 所以,flags的参数是一堆宏,他的二进制位不重叠,一次可以传多个宏

但是发现用open打开的log.txt权限是乱码(根本没有s权限)

 因为用open带上写选项(写的flags)之后,需要对写完之后的文件权限修改

也就是

之前学习过八进制语法:

进制语法. chmod命令可以使用八进制数来指定权限 

这里的mode_t就是输入对应的八进制数即可更改文件的权限

这里0表示接下来的数值是八进制表示

rwx:4+2+1=7

666表示文件的权限都设置成rw- 

但是此时的文件权限还是原来的样子

是因为umask掩码,那么怎么可以在我自己的进程短暂改变掩码?

 我自己的进程有个掩码,系统的掩码,到底这个进程的掩码听谁的?

就近原则,现在我在自己程序设置掩码,肯定是我自己的比系统的更亲

 此时设置成功

再来看一下这个open函数的返回值是多少?

记住这个3~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

  • close 

与open对应的就是close()

这个fd是文件描述符~~~究竟他是什么我们后面惠更清晰的讲解,刚才open的返回值就是fd=3 

 那么输入3给close,他就能找到对应的被打开的文件,从而关闭他

是不是感觉很神奇,fd就像密码一样

  • write 

 把buf中n个字节内容写入到fd对应的文件中

最后返回实际写入的字符数,如果写入失败返回-1并且设置errno变量

如果成功返回值>=0

简单演示一下

要不要+1是考虑要不要加上\0

此时没+1 

很明显是正确的

为什么不加?

因为字符串以\0结尾是C语言的规定不是文件的规定!!!!! 

  • read

 把文件中的内容读到buf中,读取count字节的内容 

最后的返回值还是实际读到的字节数,暂时我们无法按行读取只能整体读

在使用系统接口进行IO的时候一定要注意\0的问题

用之前的log.txt里面有hello\n 


那么语言和我们今天讲的接口有什么关系?

库函数的底层调用:系统调用

小总结:

fopen,fclose,fwrite/fputs,fread/fgets ——库函数

open,close,write,read——系统调用

他们的关系式库函数封装了系统调用!!!!!!!!!!!


文件描述符

fd(file descriptor)

任何一个进程启动的时候默认会打开当前进程的三个文件

标准输入——键盘文件

标准输出——显示器文件

标准错误——设备文件——显示器文件

 结果

说好的标准输出和标准错误都会向显示器打印,但是他们本质不一样

还记不记得我们之前在open的时候返回值fd=3

那么为什么是3,不是0 ,1,2

并且还发现

  

 这些被打开文件的fd居然是连续的!!!!!!!

这让人不禁想起数组

因为我觉得这些被打开文件肯定也是有人帮我维护的,维护就需要一定的数据结构,那我猜测这种数据结构就是数组!

真的 是这样!

因为0 1 2已经被操作系统占用了。所以只能从3开始

文件描述符:本质是数组下标 

是什么数组的下标?

当进程要打开一个文件时:

OS在内存中创建一个struct_file对象(为了把磁盘中的对应文件加载到内存)

找到是哪个进程要打开文件,用这个进程的struct files_struct* files找到struct files_struct 进而找到内部fd_array[]数组,从0下标向下遍历到一个没被占用的下标(这里很重要,星号标记*)

0 1 2默认被系统占用,找到3(假设)把创建好的struct_file对象的地址填入下标为3的数组中,向应用层返回文件描述符3!!!!

所以上层只要拿到3就可以像密码一样打开后面的很多函数(系统调用) ,但是作为用户他并不知道OS为他做了什么~

我们所谓的IO类(read,write函数)本质就是拷贝函数——用户空间和内核空间进行数据的来回拷贝

具体过程如下

那么为什么要用fd_argv[ ]里面放file* 的方法做映射?

实现模块解耦

如何理解一切皆文件?

下回分说~ 

猜你喜欢

转载自blog.csdn.net/weixin_71138261/article/details/130607195