当前位置: 首页 > news >正文

漳州招商局规划建设局网站苏州网站建设方案

漳州招商局规划建设局网站,苏州网站建设方案,培训计划模板,php网站建设网站话接上篇: 1.文件描述符fd 磁盘文件 VS 内存文件? 当文件存储在磁盘当中时,我们将其称之为磁盘文件,而当磁盘文件被加载到内存当中后,我们将加载到内存当中的文件称之为内存文件。磁盘文件和内存文件之间的关系就像程…

话接上篇: 

 1.文件描述符fd

磁盘文件 VS 内存文件?

        当文件存储在磁盘当中时,我们将其称之为磁盘文件而当磁盘文件被加载到内存当中后,我们将加载到内存当中的文件称之为内存文件。磁盘文件和内存文件之间的关系就像程序和进程的关系一样,当程序运行起来后便成了进程,而当磁盘文件加载到内存后便成了内存文件。

        进程想要访问文件必须先打开文件,一个进程可以打开多个文件,而系统当中又存在大量进程,也就是说,在系统中任何时刻都可能存在大量已经打开的文件,已经打开的文件会被加载到了内存中,这些文件也叫内存文件,反之,没有打开的文件就叫做磁盘文件。那么操作系统就要管理这些打开的文件

        如何管理就是先描述,再组织操作系统为每个已经打开的文件创建各自的struct file结构体,然后将这些结构体以双链表的形式连接起来,那么操作系统对文件的管理也就变成了对这张双链表的增删改查等操作,在每个节点中不仅有链表的指针,还应该存在着文件的内容+属性,这些信息大部分在磁盘中就保留在文件内部了,加载的时候就从磁盘中把数据加载到内存。

        而为了区分已经打开的文件哪些属于特定的某一个进程,我们就还需要建立进程和文件之间的对应关系。

进程和文件之间的对应关系是如何建立的?

当进程运行的时候,操作系统会将该程序的代码和数据加载到内存,然后创建对应的task_struct, mm_struct, 页表等…

        task_struct 里面有一个指针,指向files_struct结构体,结构体里面有名为fd_array的指针数组,该数组的下标就是文件描述符fd。

使用read和write的时候要传入文件描述符,通过文件描述符找到这个数组中的指针,进而对文件访问。

        当进程打开log.txt文件时,我们需要先将该文件从磁盘当中加载到内存,形成对应的struct file,将该struct file连入文件双链表,并将该结构体的首地址填入到fd_array数组当中下标为3的位置,使得fd_array数组中下标为3的指针指向该struct file,最后返回该文件的文件描述符给调用进程即可。

因此,我们只要有某一文件的文件描述符,就可以找到与该文件相关的文件信息,进而对文件进行一系列输入输出操作。

注意: 向文件写入数据时,是先将数据写入到对应文件的缓冲区当中,然后定期将缓冲区数据刷新到磁盘当中。

1.1.文件描述符的分配规则

我们之前连续打开了6个文件,我们发现文件描述符是从3开始的,并且是连续地址的。那真的是一直从3开始吗?下面我们看一段代码:

  #include<stdio.h>  #include<string.h>                                                                                                                              #include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>int main(){              close(0);int fd1=open("./log1.txt",O_WRONLY|O_CREAT,0644);int fd2=open("./log2.txt",O_WRONLY|O_CREAT,0644);int fd3=open("./log3.txt",O_WRONLY|O_CREAT,0644);int fd4=open("./log4.txt",O_WRONLY|O_CREAT,0644);printf("%d\n",fd1);printf("%d\n",fd2);printf("%d\n",fd3);printf("%d\n",fd4);close(fd1);close(fd2);close(fd3);close(fd4);return 0;}

 

我们发现怎么fd从0开始了,而之后的又是从3开始了。现在我们在将2也关了,我们再来看结果会是如何。

  #include<stdio.h>  #include<string.h>                                                                                                                              #include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>int main(){              close(0);close(2);int fd1=open("./log1.txt",O_WRONLY|O_CREAT,0644);int fd2=open("./log2.txt",O_WRONLY|O_CREAT,0644);int fd3=open("./log3.txt",O_WRONLY|O_CREAT,0644);int fd4=open("./log4.txt",O_WRONLY|O_CREAT,0644);printf("%d\n",fd1);printf("%d\n",fd2);printf("%d\n",fd3);printf("%d\n",fd4);close(fd1);close(fd2);close(fd3);close(fd4);return 0;}

 我们发现0和2也被用起来了。现在我们就明白了文件描述符的分配规则是从最小的未被使用的下标开始的

事实上

Linux下进程默认会打开三个文件描述符,0:标准输入、1:标准输出、2:标准错误。

        0,1,2对应的物理设备一般是:键盘、显示器、显示器。

我们之前验证了文件描述符默认是从3开始的,也就是说0,1,2是默认被打开的。

  • 0代表的是标准输入流,对应硬件设备为键盘;
  • 1代表标准输出流,对应硬件设备是显示器;
  • 2代表标准错误流,对应硬件设备为显示器。

当一个进程被创建时,OS就会根据键盘、显示器、显示器形成各自的struct file,将这3个struct file链接到文件的双链表当中,并将这3个struct file的地址分别填入fd_array数组下标为0、1、2的位置,至此就默认打开了标准输入流、标准输出流和标准错误流。

        文件描述符的分配规则:分配最小的,没有被占用的。如果我把0号关闭,那么为新文件分配的时候就从最小的0分配。

2.重定向

2.1.输出重定向

1.输入重定项。

我们之前学习过的输出重定向就是,将我们本应该输出到显示器上的数据重定向输出到另一个文件中。那他的原理是什么了?

例如: 如果我们想让本应该输出到“显示器文件”的数据输出到log.txt文件当中,那么我们可以在打开log.txt文件之前将文件描述符为1的文件关闭,也就是将“显示器文件”关闭,这样一来,当我们后续打开log.txt文件时所分配到的文件描述符就是1。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{close(1);// 打开文件int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);if (fd < 0){perror("open");exit(1);}// 打开成功printf("fd: %d\n", fd);printf("fd: %d\n", fd);printf("fd: %d\n", fd);printf("fd: %d\n", fd);fprintf(stdout, "hello fprintf\n");const char* s = "hello fwrite\n";fwrite(s, strlen(s), 1, stdout);fflush(stdout);// 关闭文件close(fd);   return 0;
}

通过上面的现象也可以看出,打印的数据没有到显示器上,而是到了磁盘的文件中,这是为什么呢?

        上面就说过,0、1、2默认是被打开的,对应的就要打开显示器,所以stdout的文件描述符就是1,所以C语言的接口fprintf认识的就是stdout或者说就是1,我们一开始就关闭了1号文件描述符,把数组下标为1的位置设置为NULL,然后打开了log.txt文件,此时1没有被占用,所以就把下标为1的位置填入log.txt的结构体的地址log.txt的文件描述符就是1了,但是上层的C语言函数认识的还是1,他们还是继续往1中写入,这样就不能打印到屏幕而是重定向到了文件中。

 

重定向的本质是在操作系统中更改fd对应的内容,上面演示的这就就叫做输出重定向。

2.2.输入重定向       

输入重定向就是,将我们本应该从一个键盘上读取数据,现在重定向为从另一个文件读取数据。

 

 比如说我们的fget函数是从标准输入读取数据,现在我们让它从log1.txt当中读取数据,我们在scanf读取数据之前close(0).这样键盘文件就被关闭,这样一样log1.txt的文件描述符就是0. 

int main()
{close(0);// 打开文件int fd = open("log.txt", O_RDONLY);if (fd < 0){perror("open");exit(1);}printf("fd: %d\n", fd);char buffer[64];fgets(buffer, sizeof(buffer), stdin);printf("%s\n", buffer);// 关闭文件close(fd);return 0;
}

关闭了0号文件描述符,所以打卡的新文件的文件描述符就变成了0,然后读取了文件中的第一行数据。 

2.3.追加重定向

还有一种就是追加重定向,更改一下选项就行了。

int main()
{close(1);// 打开文件int fd = open("log.txt", O_WRONLY | O_APPEND | O_CREAT);if (fd < 0){perror("open");exit(1);}printf("%d\n", fd);fprintf(stdout, "append success\n");fflush(stdout);// 关闭文件close(fd);return 0;
}

【注意】:“>”输出重定向修改的只是1号也就是stdout标准输出,所以尽管程序中有两行代码,一行向1号文件描述符中打印,另一行向2号文件描述符中打印,那么使用输出重定向只会使1号文件描述符重定向,2号还是打印到显示器上。

 

2.4.dup2

我们发现我们上面只能通过close关闭对应的文件描述符实习对应的输出重定向和输出重定向,那我们能不能不关闭呢?

要完成重定向我们只需对fd_array数组当中元素进行拷贝即可。

例如,我们若是将fd_array[3]当中的内容拷贝到fd_array[1]当中,因为C语言当中的stdout就是向文件描述符为1文件输出数据,那么此时我们就将输出重定向到了文件log.txt。而在linux当中就给我们提供了这个系统调用:

  • 函数功能: dup2会将fd_array[oldfd]的内容拷贝到fd_array[newfd]当中。
  • 函数返回值:调用成功返回0,失败返回-1

使用的过程中需要注意:

  1. 如果oldfd不是有效的文件描述符,则dup2调用失败,并且此时文件描述符为newfd的文件没有被关闭。
  2. 如果oldfd是一个有效的文件描述符,但是newfd和oldfd具有相同的值,则dup2不做任何操作,并返回newfd。

        只需要把想要重定向的文件在数组中拷贝过去,比如我想要输出重定向,重定向到某个文件,那么1就代表标准输出,所以就要改变1的指向,就把3的地址拷贝过去,这样1就指向了重定向的文件。 

 

输入重定向也是一样的,0是标准输入,就要从其他文件输入,就把其他文件的地址拷贝到0的位置。 

下面通过dup2演示一下前面的输出重定向:

  1 #include<stdio.h>2 #include<sys/types.h>3 #include<sys/stat.h>4 #include<unistd.h>5 #include<fcntl.h>                                                                                                                               6 int main()7 {8   int fd=open("./log.txt",O_WRONLY|O_CREAT,0644);9    dup2(fd,1);10  printf("hello world\n");11  printf("hello world\n");12 13 }

http://www.yayakq.cn/news/515818/

相关文章:

  • 网站建设成都创新互联新氧网站头图怎么做的
  • 兰州新区规划建设管理局网站网站 手机 微信 app
  • wordpress能导出网站吗网站制作制作公司
  • 快速做网站软件青海省建设工程信息网站
  • 蓝韵网络专业网站建设怎么样广告推广策略
  • 网站建设研究方法福建建设工程招投标信息网
  • 免费茶叶网站建设上海seo公司
  • 买手机的网站大良网站制作
  • 广州网站开发解决方案任务网站(做任务学技能的)
  • 佛山网站建设永网网站在线配色
  • 株洲做网站渠道电话百度提交网站收录
  • 做消防哪些网站找工作便宜网站建设成都
  • 昆明网站排名优化报价市场推广计划
  • 高端大气网站设计欣赏太原网站建设杰迅科技
  • 兰州网站程序建设网站seo查询
  • 假发网站是怎么做的怎样做企业网站
  • 网站如何设置广告商城网站制作 价格
  • 网站设计咨询网站高水平网站运营托管
  • 特定ip段访问网站代码高端网吧电脑配置清单
  • 深圳网站建设公司建设西安网页设计工作
  • 仿制网站侵权行为建湖网站设计
  • 深圳手机商城网站设计费用做网站前期预算
  • 达州建网站深圳网站建设工作
  • 柳城企业网站建设价格加盟装修公司怎么合作
  • 米各庄网站建设图片上传网站源码
  • 网站dns刷新免费的网站制作平台
  • 网站开发技术描述遵义网站建设优化公司
  • 如何更快的让百度收录网站深圳建网站一般多少钱
  • 企业网站域名做白酒的网站
  • 东莞网站建设基础安卓开发