[Linux]基础IO(上)--理解文件系统调用、文件描述符、万物皆文件

一、文件的理解

        每种语言都有进行文件操作的函数接口,例如C语言的fopen、fwrite、fprintf等等,但是进行文件操作的前提是代码已经跑起来,因为文件的打开与关闭要通过CPU来运行程序代码,所以打开文件的本质是进程打开文件,文件操作也是进程进行文件操作。

        既然文件的打开与关闭是依靠进程的,而操作系统中避免不了存在许多进程,那么一定有大量打开的文件,所以OS就需要将这些文件管理起来(先描述在组织),所以在OS内部,每一个被打开的文件应该有一个专门描述文件的结构,类似于PCB

        文件没有被打开的时候是在哪里呢?

------解释:

        文件没有被打开的时候是存在磁盘中的,而磁盘属于硬件,用户要进行文件操作是不可以直接访问硬件的,因为操作系统不相信任何人,用户只能通过操作系统的函数调用来进行文件操作,而我们在平常一般使用的是语言层面的文件函数接口,不同语言对于文件的函数调用却是有差异的,但它们都是对系统调用接口的封装。

二、文件系统调用接口介绍

1. 打开文件:open
   #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);
  • pathname: 要打开或创建的目标文件
  • flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行 “” 运算,构成flags。
  • mode:给新创建的文件设置权限
  • flag参数:
  1. O_RDONLY: 只读打开
  2. O_WRONLY: 只写打开
  3. O_RDWR : 读,写打开
  4. 这三个常量,必须指定一个且只能指定一个
  5. O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
  6. O_APPEND: 追加写
  7. O_TRUNC :如果文件存在再次以写方式打开清空文件
2. 关闭文件:close
#include <unistd.h>int close(int fd);
3. write
#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);
4. read
#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);
代码演示:

以写的方式打开文件,若文件不存在则创建文件,再次向文件写入向后追加

  #include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#include<string.h>int main(){int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);const char* buf="hello Linux file!";                                                                                                                                                       write(fd,buf,strlen(buf));close(fd);return 0;}

5. 如何理解open中的标记选项

        在日常写程序时,我们想创建一个标记一般会直接定义 int flag ,如果需要两个则定义

int flag1 、int flag2 ,若需要多个标记的话这样写不仅难以维护而且有点浪费空间。

       做标记无非就是要表达有或没有、是或不是的信息,一个整形变量有32个比特位,

每个比特位都单独可以做为标记位,这是OS设计系统调用的常用方式。接下来我们自己模拟实现一个位图的函数理解一下:

  #include<stdio.h>#define ONE (1)      //1#define TWO (1<<1)   //2#define THREE (1<<2) //4#define FOUR (1<<3)  //8void print(int flag){if(flag&ONE)printf("one\n"); //替换成其他功能if(flag&TWO)printf("two\n");if(flag&THREE)printf("three\n");if(flag&FOUR)printf("four\n");}int main(){print(ONE);printf("\n");print(TWO);printf("\n");print(ONE|TWO);printf("\n");print(ONE|TWO|THREE);printf("\n");return 0;                                                                                                                                                                                  }

 三.理解open返回值(文件描述符)

为什么fd是从3开始的呢?0、1、2去哪里了呢?

--- 0:标准输入流(键盘)

--- 1:标准输出流(显示器)

--- 2:标准错误流(显示器)

这三个流在程序启动时就自动开启了 ,Linux下万物皆文件,操作系统将这三个标准也视为文件,所以文件创建时是从3开始的

既然0、1就可代表键盘与显示器,那向显示器打印信息除了printf还可以这样做:

为什么一个整数就可以代表一个文件呢?文件描述符的本质是什么?

---- 上面说过,操作系统需要将打开的文件进行管理,区分哪些文件被打开了,哪些文件马上就要关闭等等信息,在Linux下,每一个打开的文件都会被struct file的结构体所描述,为了便于管理,会将这些结构体用双链表进行连接管理,这个结构体中还存在一个指针,表示文件内核级的缓冲区,想要读取磁盘的文件中内容,只需将内容放入该缓冲区,程序就可以使用这些内容了,同理若想要向磁盘中的文件写入内容,需要将内容先写入缓冲区,再讲缓冲区的内容导入文件,这样对文件管理只需要对文件的struct file进行管理了

对文件管理的实质是进程对文件进行管理,那进程是如何管理自己文件的呢?

        进程在创建时会创建自己的PCB,一个进程可以打开多个文件,为了区分这些文件具体是哪些进程管理的,每个进程的PCB中存在着一个struct files_struct* 的指针,这个指针用来管理进程打开的文件,为了进程与文件的对应关系,struct files_struct结构体中保存着struct file* [ ]的指针数组,既然是数组一定会有数组下标,则操作系统会将0号下标指针指向保存标准输入的struct file的地址,将1号下标指针指向保存标准输出的struct file的地址,将2号下标指针指向保存标准错误的struct file的地址,同理将3号下标指针指向自己打开的文件struct file的地址

综上所述:

# 文件操作符的本质就是文件映射关系数组的下标,所以一个整数就可以访问一个文件

# open过程的操作:

    1.创建file

    2.开辟文件缓冲区,传输文件数据(延后)

    3.查询文件描述符表,构建映射关系

    4.返回下标

四.理解Linux下万物皆文件

        在上文中,我们谈到操作系统将键盘与显示器等也看做文件,但是他们本身为硬件,该怎么理解万物皆文件呢?在Linux下是怎么做到的?

        对于设备其实我们关心的数据就两个,属性与操作方法,对于属性一个结构体就可以描述,而方法的话,不同设备的方法一定是不同的,但是可以把他们的参数与返回值设置的类型相同。

        操作系统在打开一个设备时,就会创建其对应的struct file,该结构体除了一些关于文件信息的内容,还会存在一些函数指针来实指向对应设备的方法,struct file结构体中一定还有一个指针指向设备的属性,可以让我们访问到,所以想要访问一个设备,只需要找到其对应的struct file通过内部函数指针或者指向描述属性结构体的指针就可以操作这个设备。在Linux下一套叫做vfs(虚拟文件系统)

         所以在上层看来,不论是磁盘级的文件还是设备级的文件不做区分,只将他们看做struct file,实现了万物皆文件

五、重新理解不同语言对文件操作的封装

        上文解释到在Linux操作系统下,进程是依靠文件描述符来操控文件的,但是C语言中对于文件操作的函数却使用的是FILE*的指针,连stdout、stdin、stderr也是FILE*类型的,其实FILE是一个结构体,封装了对于文件信息的描述,其内部也一定包含了文件描述符。

  #include<stdio.h>  #include<sys/types.h>  #include<sys/stat.h>  #include<fcntl.h>  #include<unistd.h>  #include<string.h>  int main()  {  FILE* fp=fopen("log.txt","w");  if(fp==NULL)  {perror("fopen");return 1;}printf("stdin:%d\n",stdin->_fileno);printf("stdout:%d\n",stdout->_fileno);   printf("stderr:%d\n",stderr->_fileno);   printf("fp:%d\n",fp->_fileno);                                                                                                                                                             return 0;                                                                                                                                                }                                                                                                                                                          

语言的文件操作函数,本质底层都是对系统调用的封装!

那C语言为什么要这样做呢?

        因为C语言(其他语言也是这样)想实现跨平台性,不同操作系统的系统调用是不同的,仅使用系统调用的代码不具有跨平台性,所以语言会对系统调用进行封装,在哪个操作系统下就使用该操作系统的系统调用,这样就可以实现语言的跨平台性。

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/780371.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iMazing2024功能强大的iPhone和iPad管理工具

iMazing是一款功能强大的iPhone和iPad管理工具&#xff0c;确实可以作为iTunes的替代品进行数据备份。以下是一些关于iMazing的主要特点和功能&#xff1a; 设备备份&#xff1a;iMazing可以备份iOS设备上的所有数据&#xff0c;包括照片、视频、音乐、应用程序等。与iTunes相比…

使用uni-app开发微信小程序并实现页面间的跳转

一、下载需要的开发工具 HBuilderX 微信开发者工具 HBuilderX HBuilderX-高效极客技巧 (dcloud.io) 微信开发者工具 下载 / 开发版更新日志 (qq.com) 二、新建项目 通过vue-cli命令行创建项目 参考&#xff1a; uni-app官网 (dcloud.net.cn) 2.1全局安装 vue-cli npm i…

Mysql数据备份与恢复实战

文章目录 备份类型备份内容备份工具mysqldump备份 实战案例&#xff1a;恢复误删除的表准备工作2:30完全备份完全备份后更新数据表10:00误删students表需要恢复还原的状态开始还原恢复 为什么要备份&#xff1f; 备份是为了&#xff1a;灾难恢复&#xff1a;硬件故障、软件故障…

Leetcode的正确打开方式

很多新手朋友在学习完数据结构与算法之后&#xff0c;都想找个平台磨练自己的技艺。那么LeetCode绝对是不二之选。但是官网刷题不是很友好&#xff0c;那么今天给大家介绍一款刷LeetCode神器。也是未来工作之后的摸鱼神器。 leetcode-editor 本打工人的摸&#xff08;nei&am…

10分钟带你用openlab搭建web网站

准备工作 虚拟机恢复快照 关闭防火墙、下载httpd&#xff0c;启动httpd服务、显示httpd服务是否开启 [rootserver ~]# systemctl stop firewalld [rootserver ~]# yum install httpd -y [rootserver ~]# systemctl start httpd [rootserver ~]# systemctl enable httpd [root…

【Java初阶(六)下】封装 继承 多态

❣博主主页: 33的博客❣ ▶文章专栏分类: Java从入门到精通◀ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; 目录 1.前言2.多态2.1多态的概念2.2多态实现条件2.3重写2.3.1避免在构造方法中调用重写的方法 2.4向上转型和向下转型2.4.1向上转型2.4.2向下转型 3.抽象类3…

常见的数学方法

Math类表示数学类&#xff0c;其中的数学方法都被定义成为static形式&#xff0c;所以可以直接通过Math类的类名调用某个数学方法。语法格式&#xff1a; Math.xxx(参数)&#xff1b; 例题 输入n个整数a1,a2,a3,......an,求这n个数的最大值max&#xff0c;最小值min&#xff0…

记录个人学习golang路线(如何学习golang,如何转golang)

最近好久没更&#xff0c;在看兔兔的博客&#xff0c;学习golang&#xff0c;兔兔的文章&#xff0c;有一定的编程经验 && 初学golang者&#xff0c;一定要看&#xff0c;如果是其他语言转golang&#xff0c;那就必须要看了&#xff0c;可以帮助你了解golang的语法&…

再见 mysql_upgrade

在数据库管理的世界里&#xff0c;随着技术的不断进步和业务的不断发展&#xff0c;数据库的版本升级成为了一个不可避免的过程。 MySQL 作为业界领先的开源关系型数据库管理系统&#xff0c;其版本迭代与功能优化同样不容忽视。 而在这个过程中&#xff0c;升级工具就显得尤为…

政安晨:【Keras机器学习实践要点】(五)—— 通过子类化创建新层和模型

目录 介绍 安装 层级&#xff1a;状态&#xff08;权重&#xff09;与某些计算的组合 层可以有不可训练的重量 最佳实践&#xff1a;推迟权重的创建&#xff0c;直到输入的形状已知。 层可以递归组合 后端不可知层和特定后端层 add_loss()方法 可以选择在您的层上启用…

C语言goto语句介绍

在C语言中&#xff0c;goto语句是一种流程控制语句&#xff0c;用于无条件地转移到程序中的特定标签位置。尽管goto语句在编程中具有一定的争议&#xff0c;但在某些情况下&#xff0c;它可以提供一种简单有效的解决方案。本文将深入介绍C语言中的goto语句&#xff0c;包括其基…

前端小白的学习之路(webpack)

提示&#xff1a;webpack简介&#xff0c;nvm,npm配置环境,常用命令&#xff0c;基本web项目构建 目录 webpack 1.配置环境 1)node.js node常用命令 2)nvm nvm常用命令&#xff1a; 3)npm npm常用命令 2.构建简易web项目 1)创建目录 2)安装webpack依赖 3)配置 webpac…

4核32G轻量云服务器优惠价格65元/月、951元一年

京东云4核32G轻量服务器优惠价格65元/月、195元3个月、476元6个月、951元一年&#xff0c;配置4C32G-100G SSD系统盘-8M带宽-1500G月流量 华北-北京&#xff0c;京东云优惠活动 yunfuwuqiba.com/go/jd 活动链接打开如下图&#xff1a; 京东云4核32G轻量服务器优惠价格 京东云&a…

Vue基础配置、组件通信

基础配置 Vue框架已经集成了webpack配置 小注意点 vbase 快速生成vue模板 组件名必须是多词格式(驼峰模式) 具体三种写法: ①小驼峰:abcDef.vue ②大驼峰&#xff1a;AbcDef.vue ③中横线&#xff1a;abc-def.vue 假如文件名不符合多次格式的补救办法&#xff1a; 导出重命名…

写作类AI推荐(二)

本章要介绍的写作AI如下&#xff1a; 火山写作 主要功能&#xff1a; AI智能创作&#xff1a;告诉 AI 你想写什么&#xff0c;立即生成你理想中的文章AI智能改写&#xff1a;选中段落句子&#xff0c;可提升表达、修改语气、扩写、总结、缩写等文章内容优化&#xff1a;根据全文…

【Vue】手写Vue工具函数hasChanged源码

function hasChanged(x,y) {}hasChanged函数接受两个参数&#xff0c;判断参数是否发生变化&#xff0c;即两个参数是否完全相同&#xff0c;发生了改变返回true&#xff0c;否则返回flase。 对象类型数据先比较值&#xff0c;相同则比较址&#xff0c;址不同也返回true。 首先…

Stable Diffusion 模型下载:epiCPhotoGasm(真实、照片)

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里&#xff0c;订阅后可阅读专栏内所有文章。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八 下载地址 模型介绍 该模型对照片是什么有很高的了解&#xff0c;所以…

泰迪智能科技荣获山东省“技能兴鲁”职业技能大赛优秀组织奖

近日&#xff0c;泰迪智能科技荣获了山东省“技能兴鲁”职业技能大赛——第四届山东省“云数”技能竞赛“优秀组织单位”。 据悉&#xff0c;山东省“技能兴鲁”职业技能大赛——第四届山东省“云数”技能竞赛是由山东电子学会、山东省信息产业协会主办的&#xff0c;该竞赛是通…

OpenHarmony OpenCV应用样例开发

背景 OpenCV 介绍 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库。它由一系列的 C 函数和少量 C 类构成&#xff0c;同时提供 Python、Java 和 MATLAB 等语言的接口&#xff0c;实现了图像处理和计算机视觉方面…

java-pytorch 使用手动下载FashionMNIST数据集进行测试

java-pytorch 使用手动下载FashionMNIST数据集进行测试 先定义训练数据和测试数据的位置查看一下读取到的标签数据格式使用loc和iloc访问下数据&#xff0c;便于下面操作使用read_image函数查看下图片的数据大小开始写数据集使用DataLoader去加载我们自己的数据看下加载后的dat…