初识Linux · 文件(2)

打印 上一主题 下一主题

主题 835|帖子 835|积分 2505

目次
前言:
文件描述符fd
默认的三个流
末了总结

前言:

由前文文件(1)的介绍,我们引出了三个题目:
   高级语言和体系调用函数之间是否存在关系?
  fd返回值的012和C语言打开的三个流是否有什么关系?
  不同的宏和不同函数的选项之间是否存在某种关系?
  这是我们文件一内里引发的题目,那么在文件(2)内里呢,我们通过对文件深层次的明确,就会知道,以上三个题目的答案了。
那么现在,我们就进入主题吧。

文件描述符fd

我们再看一眼open函数和write函数:

返回值的描述是:返回值新的文件描述符,如果堕落了返回的是-1。
那么我们研究的是这个返回值。
首先,我们知道打开文件的是历程,而非我们,那么文件的集中管理,实际上是由历程的task_struct有一个文件指针,struct file_struct* files,指向的一块文件结构体->struct files_struct,对于该结构体而言,管理的是另一个结构体,即由文件组成的结构体,它们之间的毗连方式是双向链表的方式。

就像如许,那么file_struct和file,两个结构体之间是怎样产生联系的呢?
此时,文件描述符就出场了:

files_struct内里有一块空间,通过下标访问,而下标指向的,就是一个一个的struct file。所以每次拿到了fd之后,就能对文件进行操纵。
但是光如许,似乎对文件明确并没有加深多少。
我们写的数据在哪里呢?
我们使用函数,内里的数据是放在哪里呢?难道是有了文件描述符fd我们就可以直接对files结构体操纵了?不是的,因为文件存储的地方是在磁盘上,而非OS内里,所以我们一定是会和磁盘扯上一定关系的,那么:

在OS内里有一块空间,缓存空间,将数据加载到了缓存内里,此时没有堕落,就可以对文件,也就是已经先描述再操纵的的文件对象内里,将数据进行写入即可。
那么我们简朴总结上面的过程就是:
文件 = 属性 + 内容,我们要修改内容,也就是要和外设打交道,那么需要OS层面管理。为了修改外设的属性,所以需要雷同驱动步伐操纵,此时OS层面的历程,也就是打开文件的软件,加上管理文件的多个结构体,联合文件描述符fd进行操纵。
那么体系调用函数open整个过程要干的事就是:
1 创建文件file 2 开辟文件缓冲区 加载文件数据 3 查找对应的文件描述符fd 4 通过file地址将数据移动 5 返回下标。

默认的三个流

文件描述符fd我们已经明确了,根据上文012是默认打开的三个流:0 对应的标准输入,1对应的标准输出,2对应的标准错误,输入比如键盘,输出和错误都是对应的表现器。
那么不同的外设,输入输出都应该有自己的一套体系,或者说有对应的函数,但是函数名往往都是不相同的,在OS层面怎样进行集中管理呢?
在OS层面存在一种结构叫做:VFS,即virtual file system。
因为每个file对象,都有一个函数指针,固然函数名不同,但是可以将函数的参数,返回值等弄的大差不差呗。此时,访问对应的外设,OS层面可以通过VFS层,对不同的外设进行访问。
可是我们说了这么多,怎样证实呢?
我们可以用file对象内里的一个变量证实,_fileno,返回值就是对应的文件描述符,而C语言的FILE指针,本质是经过typedef的,封装的是体系内里的file,所以FILE指针直线的对象肯定也是有_fileno的,我们使用如下代码证实:
  1. int main()
  2. {
  3.     FILE* fp = fopen("log.txt","w");
  4.     printf("fp->%d\n",fp->_fileno);
  5.     printf("stdin->%d\n",stdin->_fileno);
  6.     printf("stdout->%d\n",stdout->_fileno);
  7.     printf("stderr->%d\n",stderr->_fileno);
  8.     return 0;
  9. }
复制代码

此时,证实完毕。

末了总结

由上文可以得出,高级语言想要使用文件描述符fd,一定是会经过封装的,否则对于外设层面是没有办法使用的。
那么,既然表现器也是个文件,我们不妨尝试对表现器这个文件进行写入,条件是我们怎样知道表现器的文件在哪里呢?
我们可以进入到根目次的dev,dev代表装备,此中:

dev目次内里的三个流也是间接证实了。

同时,我们进入到pts目次,再开一个终端,就会发现:

也就是说,新开的终端的文件是5号,那么,我们可以:
  1. int main()
  2. {
  3.     int fd = open("/dev/pts/5", O_WRONLY|O_APPEND);
  4.     if(fd < 0) return 1;
  5.     const char *message = "hahaha\n";
  6.     while(1)
  7.     {
  8.         write(fd, message, strlen(message));
  9.         sleep(1);
  10.     }
  11.     close(fd);
  12.     return 0;
  13. }
复制代码

此时,就在一直打印了。
所以,高级语言的全部文件操纵函数,都是对体系调用的封装!!
那么,我们之后是保举使用高级语言的函数还是体系调用呢?
当然是高级语言的了,因为体系调用的函数不具有跨平台性!!
文件我们也算是明确了部分了,下文之后,就是应用层面的了,比如重定向,比如语言级别的缓冲区。

感谢阅读!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

盛世宏图

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表