Linux——IO之系统接口+文件描述符详解

news2024/12/23 17:33:20

IO

  • 文件再次理解
  • 系统接口文件操作
  • 理解文件描述符 fd

文件再次理解

文件 = 文件内容 + 文件属性
其中文件属性也是数据–>即便你创建一个空文件,其也是要占据磁盘攻坚的。
文件操作 = 文件内容的操作 + 文件属性的操作
有可能在操作文件的过程中即改变文件的内容,又改变文件的属性。
我们在打开文件的时候,系统会将文件的属性加载到内存中
因为根据冯诺依曼体系结构,CPU需要对文件进行读写的话,需要对内存进行读写。
系统中的文件大致可以分为两类
打开的文件是内存文件,没有打开的文件在磁盘上静静的躺着可以称为磁盘文件。
通常我们所说的打开文件,访问文件关闭文件,是谁在进行相关操作?
一般是fopen,fclose,fread,fwrite... 这是我们的代码,然后将代码编译了二进制可执行程序 ,只有文件运行起来的时候,才会执行相应的代码,然后才会正真的对文件进行相关操作。所以是真正对文件进行操作的是进程
什么是当前路径?
看下列代码

{                                                                                                   
  5 
  6   FILE *fp = fopen("log.txt", "w");//写入
  7   if(fp == NULL) {
  8     perror("fopen");
  9     return 1;
 10   }
 11   printf("mypid: %d\n", getpid());
 12   while(1) {
 13     sleep(1);
 14   }
 15    //fprintf 将特定的数据格式化显示到文件流中
 16    const char *msg = "hello zjt";
 17    int cnt = 1;
 18    while(cnt < 20) {
 19      fprintf(fp, "%s: %d\n", msg, cnt++);
 20    }
 21    fclose(fp);
 22    printf("为什么不能创建文纪念\n");
 23   return 0;
 24 }

运行后发现
在这里插入图片描述
此时如果chdir更改当前的进程路径

chdir("/home/zjt");//更改当前进程的工作路径

在这里插入图片描述
所以当前路径并不是指源代码所在路径下,实际上指的是当前进程所在的路径下,也就是进程的工作路径,只不过默认情况下进程的工作路径是他当前自己所处的路径,不过这是可以改的。

在这里插入图片描述

小结一下 open打开方式

a:追加重定向,不断向文件中新增内容
w:以w方式打开文件时,准备写入的时候,其实文件已经被清空了

在这里插入图片描述
所以我们可以推导出,所有语言都对系统接口做了封装,C语言也对系统接口做了封装,对于其他语言而言,对于不同的系统接口的封装就类似于多态,也就是说,在最上层的接口调用都一样的,但是底层对于不同系统而言,其调用的结果是不一样的。C语言对系统接口的封装采用的是最直接的穷举所有的底层接口 + 条件编译做到的

为什么要封装?

  1. 因为原生系统接口,对于普通程序员而言,使用的成本比较高
  2. 而且如果直接使用系统接口的话,语言不具有跨平台性,不同系统的接口实现都是不一样的。

我们为什么要学习文件级别的系统接口?
因为万变不离其中,所有的语言,只要是文件操作,其最底层都会调用系统接口,只要我们将最本质的系统接口学习了,那么学习其他的语言最上层的调用就会得心应手了!

系统接口文件操作

open函数
在这里插入图片描述
O_RDONLY:以只读模式打开文件。
O_WRONLY:以只写模式打开文件。
O_RDWR:以读写模式打开文件。
上述三个宏如果文件不存在就会报错
O_CREAT:如果指定的文件不存在,则创建一个新的文件。如果文件已经存在,则不执行任何操作。需要指定文件的访问权限,
O_APPEND:在文件末尾追加;
O_TRUNC:将文件阶段清空

1 #include<stdio.h>
  2 #define PRINT_A 0x1 // 0001
  3 #define PRINT_B 0x2 // 0010
  4 #define PRINT_C 0x4 // 0100
  5 #define PRINT_D 0x8 // 1000
  6 #define PRINT_DFL 0x0
  7 
  8 //类比open函数
  9 void Show(int flags)
 10 {
 11   if(flags & PRINT_A) printf("hello 我是A\n");
 12   if(flags & PRINT_B) printf("hello 我是B\n");
 13   if(flags & PRINT_C) printf("hello 我是C\n");
 14   if(flags & PRINT_D) printf("hello 我是D\n");
 15   if(flags == PRINT_DFL) printf("hello 我是Default\n");
 16 }
 17 int main()
 18 {
 19 
 20   printf("打印default\n");
 21   Show(PRINT_DFL);
 22   printf("打印A\n");
 23   Show(PRINT_A);
 24   printf("打印B\n");
 25   Show(PRINT_B);
 26   printf("打印A和B\n");
 27   Show(PRINT_A | PRINT_B);
 28   printf("打印C和D\n");
 29   Show(PRINT_C | PRINT_D);                                                                          
 30   return 0;
 31 }
~

在这里插入图片描述
这就是传宏标志的一种好的做法。
打开文件的系统调用接口有多重,但向文件写入的接口只有write
在这里插入图片描述

打开不存在的文件只能用三个参数的open
第三个参数表示文件的权限,打开已存在的文件用两个参数的open

 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 #include<sys/stat.h>
  5 #include<fcntl.h>
  6 #include<string.h>
  7 
  8 int main()
  9 {
 10 
 11   umask(0);//umask设置为0,以确定的方式打开文件
 12   int fd = open("log.txt", O_WRONLY | O_CREAT,  0666);//设置文件的基本权限
 13   if(fd < 0) {
 14     perror("open error");
 15     return 1;
 16   }
 17   printf("fd: %d \n",fd);
 18   int cnt = 0;
 19   const char *str = "我是一个即将要被写入的缓冲区\n";
 20   while(cnt < 5) {
 21     write(fd, str, strlen(str));//此时strlen不用加1,因为\0是C语言独有的标志,与系统无关
 22     ++cnt;                                                                                          
 23   }
 24   close(fd);
 25   return 0;

在这里插入图片描述
将上述代码只改一部分运行后显示下面的情况
在这里插入图片描述

在这里插入图片描述
说明系统调用的W与C语言中的"w"是不一样的,C语言fopen的"w"
对应着系统调用的三个接口O_WRONLY | O_CREAT | O_TRUNC
eg
在这里插入图片描述

在这里插入图片描述
因此还是C语言较方便,同时C语言还有一些fopen打开方式是以格式化写入等所以系统接口的调用非常麻烦
read函数
在这里插入图片描述

  umask(0);//umask设置为0,以确定的方式打开文件  
 12  // int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);//设置文件的基本权限  
 13    int fd = open("log.txt", O_RDONLY);  
 14   if(fd < 0) {  
 15     perror("open error");  
 16     return 1;  
 17   }  
 18   printf("fd: %d \n",fd);
 19   char buffer[128];
 20   //因为read读取文件的第二个参数是不关心数据是什么类型的
 21   //但是我们还是得把它当做字符串类型,所以在最后加一个'\0'                                          
 22   ssize_t s = read(fd, buffer, sizeof(buffer) - 1);                   
 23   if(s > 0) {                                                         
 24     buffer[s] = '\0';                                                 
 25     printf("%s\n",buffer);                                            
 26   }                                            

在这里插入图片描述

理解文件描述符 fd

 umask(0);//umask设置为0,以确定的方式打开文件
 12 
 13   int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);//设置文件的基本权限
 14   int fda = open("loga.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);//设置文件的基本权限
 15   int fdb = open("logb.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);//设置文件的基本权限
 16   int fdc = open("logc.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);//设置文件的基本权限
 17   int fdd = open("logd.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);//设置文件的基本权限
 18   printf("fd:  %5d\n",fd);                                                                          
 19   printf("fda: %5d\n",fda);
 20   printf("fdb: %5d\n",fdb);
 21   printf("fdc: %5d\n",fdc);
 22   printf("fdd: %5d\n",fdd);

此时运行
在这里插入图片描述
两个问题

  1. 为什么从3开始,0,1,2呢?
    在这里插入图片描述
    下面我们验证一下文件描述符0,1,2就是标准输入标准输出标准错误。
//FILE*是结构体指针,在结构体指针一定能找到文件描述符
 14    printf("stdin: %d\n",stdin->_fileno);
 15    printf("stdout:%d\n",stdout->_fileno);
 16    printf("stderr:%d\n",stderr->_fileno); 

在这里插入图片描述
在这里插入图片描述

总结:C语言的接口一定封装了系统接口
2. 0,1,2,3,4,5…你见过什么数据是这个样子的?
数组下标
因为用的都是系统接口,所以这些数组下标也就是操作系统的返回值。
一个进程是可以打开多个文件的,所以进程 :文件 = 1:n
所以在系统中,有可能会存在大量的被打开的文件,OS需要对这些文件做管理,所以先描述在组织

在这里插入图片描述
此时又产生了一个问题:
stdin,stdout,stderr对应的分别是键盘,显示器,显示器这些都是硬件,也用上述的struct file来标识对应的文件吗?

在这里插入图片描述

在这里插入图片描述
我们可以在源码中证明上述体系结构的存在

在这里插入图片描述

所以所为的数组下标实在内核当中为该进程建立和对应文件的一种映射关系的一种方式

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

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

相关文章

Linux---echo命令、反引号`、tail命令、重定向符

1. echo命令 可以使用echo命令在命令行内输出指定内容 语法&#xff1a;echo 输出的内容 无需选项&#xff0c;只有一个参数&#xff0c;表示要输出的内容&#xff0c;复杂内容可以用 ”” 包围 带有空格或 \ 等特殊符号&#xff0c;建议使用双引号包围。 如果不使用双引号…

华为OD机试真题 Java 实现【统计匹配的二元组个数】【2023Q2 200分】

一、题目描述 给定两个数组A和B&#xff0c;若数组A的某个元素A[i]与数组B中的某个元素B[j]满足 A[i] B[j]&#xff0c;则寻找到一个值匹配的二元组(i, j)。 请统计在这两个数组A和B中&#xff0c;一共存在多少个这样的二元组。 二、输入描述 第一行输入数组A的长度M&…

复习之[ 查询帮助 ] 和 [ 输入输出管理 ]

1.查询命令用途--whatis # whatis 命令 : 查询命令的用法 -如果结果出现nothing , 有两种情况&#xff1a; &#xff08;1&#xff09;查询数据库没有更新&#xff0c;此时输入命令 mandb更新数据库即可。 &#xff08;2&#xff09;查询的命令不存在。 2.获得命令的简要帮…

想学渗透,如何入门?

首先 渗透是计算机技术应用的一种&#xff0c;脱离不了基础&#xff0c;您需要学会一门编程语言&#xff0c;任何与计算机相关的都是从学习编程语言开始的&#xff0c;让你对计算机有个初步的认识&#xff0c;将您认识的数字转化为用0和1表示的编码。这个阶段推荐学习Python&a…

​LeetCode解法汇总LCP 33. 蓄水

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣 描述&#xff1a; 给定 N 个无限容量且初始均空的水缸&#xff0c;每个水缸配有一个水桶用来打水&…

华芯微特SWM34-IO速度优化

对比测试了一下IO翻转速度在各种函数调用的情况下的差异 CPU运行速度150Mhz,SDRAM开 直接调用翻转函数 while(1) {GPIO_InvBit(GPIOA, PIN0)&#xff1b; }速度大约5Mhz&#xff0c;主要是因为函数调用开销和函数内部的移位和异或操作&#xff0c;增加了指令的运行数量。 vo…

这是JWT 简单使用

JWT 是 Json Web Token的缩写 JSON Web Tokens - jwt.ioJSON Web Token (JWT) is a compact URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is digitally signed using JSON Web Sig…

6-索引

目录 1.什么是索引&#xff1f; PS&#xff1a;数据库引擎简介&#xff08;InnoDB VS MyISAM&#xff09; 2.为什么需要索引&#xff1f; PS&#xff1a;存储数据模组 PS&#xff1a;查询数据存储的目录&#xff1a; 3.索引的作用 PS&#xff1a;索引 VS 书的目录 4.索…

PostgreSQL 源码部署

文章目录 说明1. 准备工作1.1 源码包下载1.2 解压安装目录1.3 安装依赖包1.4 添加用户1.5 创建数据目录 2. 编译安装2.1 源码编译2.2 配置环境变量2.3 初始化数据库2.4 启动数据库2.5 连接数据库 3. 参数调整3.1 配置 pg_hba3.2 监听相关2.4 日志文件2.5 内存参数 说明 本篇文…

db2常用命令/db2常见报错

文章目录 一、前言二、db2服务端常用命令2.1 启动/停止数据库2.2 连接数据库2.3 查看schema下所有表名2.4 查看表结构2.5 删除表数据2.6 导入导出del/ixf文件2.6.1 del与ixf区别 三、db2客户端常用命令3.1 查看schema下所有表及每个表的记录数3.2 修改表字段&#xff0c;对表字…

WPF中集合ObservableCollection<T>的使用

C#集合类ObservableCollection<T> 类似于泛型列表类List<T>&#xff0c;表示一个动态数据收集&#xff0c;该集合在添加或删除项或刷新整个列表时提供通知。 所在命名空间&#xff1a;System.Collections.ObjectModel 继承关系&#xff1a; public class Obser…

APP软件开发详细流程如何?

在互联网技术发达的今天&#xff0c;APP已经深入到我们生活的方方面面了&#xff0c;从购物、家政、洗车、教育到美容、旅游、餐饮等等&#xff0c;都可以通过各种各样的APP软件来实现&#xff0c;使我们的生活更加便捷化、智能化。不过&#xff0c;很多感兴趣的朋友对于APP软件…

亚马逊云科技宣布全面推出Amazon Aurora I/O-Optimized集群配置

自亚马逊云科技Amazon Aurora于2014年推出以来&#xff0c;成千上万的客户选择Aurora来运行其要求最严苛的应用程序。Aurora在全球范围内提供无与伦比的高性能和可用性&#xff0c;完全兼容MySQL和PostgreSQL&#xff0c;成本仅为商用数据库的十分之一。 许多亚马逊云科技客户受…

电竞小程序系统开发功能有哪些?

电竞小程序系统开发功能有哪些&#xff1f; 1、电竞资讯。对于电竞爱好者来说&#xff0c;每一场电竞比赛的相关信息都是不容错过的&#xff0c;因此用户可以通过小程序直接了解近期电竞相关资讯&#xff0c;例如&#xff1a;赛程安排、直播平台、参赛团队、比赛规则等&…

【CocosCreator问题总结】MotionStreak效果显示异常

&#x1f4e2;博客主页&#xff1a;肩匣与橘&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由肩匣与橘编写&#xff0c;首发于CSDN&#x1f649;&#x1f4e2;生活依旧是美好而又温柔的&#xff0c;你也是✨ …

公司新招了一个00后软件测试工程师,上来一顿操作给我看呆了...

前段时间公司新来了个同事&#xff0c;听说大学是学的广告专业&#xff0c;因为喜欢IT行业就找了个培训班&#xff0c;后来在一家小公司干了三年&#xff0c;现在跳槽来我们公司。来了之后把现有项目的性能优化了一遍&#xff0c;服务器缩减一半&#xff0c;性能反而提升4倍!给…

基于微信小程序的医院挂号预约系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

react学习2

props基本用法&#xff0c;把属性自动保存到props里 简写&#xff1a;三点展开&#xff0c;展开运算符无法展开对象&#xff0c;但是三点外侧包裹花括号可以复制对象{...P} 对props的属性进行限制 首先需要引入prop-types.js包 之后再去进行限制 props是只读的&#xff0c;只…

Vue之数据代理(getter、setter)

文章目录 前言一、数据代理1.Object.defineProperty()2.数据代理讲解 总结 前言 Object.defineProperty 数据代理 一、数据代理 1.Object.defineProperty() &#xff08;1&#xff09;实例对象可以通过Object.defineProperty()方法来添加属性&#xff0c;但是添加的属性默认…

进击的Mini LED:群雄逐“屏”,谁主沉浮

前不久&#xff0c;素有家电产业“风向标”之称的中国家电及消费电子博览会AWE在上海圆满闭幕。作为全球三大顶级家电与消费电子展会之一&#xff0c;每年各家企业都会携各自尖端技术亮剑上海滩&#xff0c;舞台中央的面孔也会逐年有些许不同&#xff0c;而从C位的演变中&#…