【Linux】基础IO认识(2)

news2024/9/21 19:01:13

基础IO认识(2)

  • 1、补充系统调用
    • 1、1、read调用
    • 1、2、stat
  • 2、重定向
    • 2、1、文件描述符的分配规则
    • 2、2、实现重定向(dup2)
  • 3、缓冲区的理解
    • 3、1、缓冲区典型实例
    • 3、2、缓冲区代码形式展示
  • 4、深化和实践利用
    • 4、1、在shell中加入重定向
    • 4、2、简单实现库的封装

1、补充系统调用

上一篇文章中已经介绍了打开还有关闭的系统调用,但是还有一些的调用没有讲到,现在就简单的讲解一下吧。

1、1、read调用

系统调用也包括了read的选项。
在这里插入图片描述
从指定文件描述符描述的文件中读取,读取到buffer中,buffer期望读取多少呢?根据count个字节来判断。

1、2、stat

stat的系统调用的作用就是类似于status。能够获取指定文件的属性。
在这里插入图片描述
图上的介绍就是,stat调用能够通过路径或者是文件描述符来获取到struct stat的结构体。
struct stat这又是什么呢?那肯定是关于文件属性的结构体啊,我们man 2 stat的时候能够看到。

其中这结构体中的变量都代表一个文件的各种属性,换句话说全部属性也都在这里了
并且这个结构体在这个函数中是一个输出型参数,当这个函数调用结束之后,能够根据所指定的文件的属性来填充其中的内容。
上面的系统调用参数想要试用的话也很简单,根据上面的参数需求,下面来演示一下。
在这里插入图片描述
在这里插入图片描述

2、重定向

2、1、文件描述符的分配规则

进程会查询自己的文件描述表,分配最小的没有被使用的fd(没有实现的难度,就相当于是遍历数组,找最小下表)。

2、2、实现重定向(dup2)

如果我们知道了上面的文件描述符的分配规则的情况下的话,如果我们关闭了fd=1的情况,并且在下面printf或者是fprintf的时候还是照样的是一个默认,另一个指向的还是stdout的话(加上fflush),此时展现的结果就是会创建一个文件,并且在文件中有着我们原本需要打印的内容,那这不就是换一种意义上的重定向的含义吗。代码如图
在这里插入图片描述
其中C语言中的这两个函数其实指向本质应该是这样:fprintf/printf->stdout->struct FILE->stdout->_fileno==1。所以底层的变化,关close(1)的时候,在上层上的C语言函数中,不能够直接看出变化,所以在上层调用的时候就还是会照样的继续去访问原本的fd==1的下标,然后继续在其中写入的话,就会在我们创建的文件中开始写入原本向现实其中显示的内容,这样不就是展示出了重定向的操作了
这样看来的话,重定向在上层没有需要操作的,需要改变的就只有OS内部fd文件操作符的变化。
可是当我们不加上fflush的话,写不进去,这又是为什么呢?缓冲区和这个又有什么关系呢?
其实是因为在C语言级别的stdin,stdout以及stderr的FILE结构体中,也包含了语言层面上的文件缓冲区,我们刚刚介绍的文件操作函数也并不是直接通过系统调用直接存放在OS中的内核文件缓冲区中,而是存放在了语言层面上的缓冲区中,也就是说,如果不刷新的话,只会存在语言缓冲区中,不会真正的写到文件内核缓冲区中,也就不会在进程结束的时候,展示出我们新写的文件。所以我们要fflush让语言层面的缓冲层刷新到系统层面上然后对文件进行写或者别的操作。
这么看的话,重定向是不是有点粗糙,每次的重定向都还需要关闭文件,然后再打开才能够实现重定向吗?
当然不是了!介绍系统调用接口dup2

要知道dup2不只是两个整数之间的拷贝,而是文件下标是代表的文件内容的拷贝。当然哪一个是old哪一个是new就需要看函数解释( 我就简单的搜一下这个调用的介绍,想要更深入的了解到话,还是自行搜搜吧)
在这里插入图片描述
看完函数解释知道newfd是oldfd的拷贝,所以要重定向的话,最后留下来的是oldfd的,所以重定向位置的文件的操作符是oldfd,原本指向显示器的fd= =1的文件操作符拷贝了oldfd的文件操作符。所以应该选2。
在这里插入图片描述
这样的话原本指向1的显示器的文件操作符的话,现在就是指向了oldfd。虽然这样的话可能会导致多个文件操作符指向同一个文件,但是不用担心,因为在struct file中会存在int ref_count,类似于引用计数。当然,原本有被指向的文件可能在ref_count == 0的时候就会自行进行关闭。

3、缓冲区的理解

缓冲区不只存在一个地方,首先得知道缓冲区有内核级缓冲区也还有用户级缓冲区但是所有的缓冲区,都有两个效果。首先就是解耦,还有一个就是提高效率
举个例子来简单化的效果的话就像是,我们平时见到的超市一样,我们需要的时候直接去超市里面拿就可以了,我们不回去跑那么远,还要去工厂中去拿,所以这种方便也就是像缓冲区一样给系统的速度增加,同时这种情况也减少了程序之间的耦合性质,我们不需要管到底怎么样才能将我们的数据存到数据之上,我们只需要把我们的数据按照键盘输入就行了。就像是,我们不需要管到底怎么样把商品弄到超市,我们只需要在超市拿就行了。
可是,我们进行数据的拷贝到缓冲区的时候难道不是会增加时间吗?怎么会减少时间的呢?我们直接把数据拷贝到文件缓冲区中这样不应该是更快吗,为什么要多花一次时间拷贝到语言层面上的缓冲区呢?
其实不然,这里的提高效率是提高谁的效率?是提高商品和超市的效率吗?不是的,提高的是客户和商品之间的效率,换句话说也就是提高使用者的效率,使用者之需要交到缓冲区就可以,并不需要等待OS进行交换数据的时间,这样的话,使用者就能够继续使用,这样的话,就能够提高使用者使用的效率。
除此之外还
不建议
多次的调用系统调用,因为系统调用也是需要消耗时间的,所以放在语言层的缓冲区,就会积攒一些之后然后再开始刷新缓冲区,启动系统调用,这是提高IO刷新的效率。
再说一下,其实对于语言来说,并不是一定要做到给我们提供缓冲区的,但是提供缓冲区的话,就能够大大的方便操作者使用的效率了,所以说,这也就是为什么C语言在当时,包括现在,流行了那么多年的原因,随着我们学习的深入,我们也逐渐理解到C语言中为我们使用者考虑到的细节,优化使用者的使用感受,也提高了系统的效率。
缓冲区的实现方式也有挺多种可能的,就比如说,只要有数据就使用fflush,刷新到OS的缓冲区,还有一种就是行刷新,现实就是这么刷新的,还有一种就是全缓冲,一般对应的就是普通文件的刷新,只有当缓冲区都写满的时候才会进行刷新。当然这都是在进程正常进行的时候才会有的状态,如果进程停止了的话,系统会自动刷新。 还有就是我们能够强制进程中的缓冲区直接刷新,最简单的例子就是使用fflush。值得注意的是这是在Linux操作系统上的缓冲区刷新规则,如果在windows上的话可能还会有所不一样

3、1、缓冲区典型实例

下面请看前提的代码
在这里插入图片描述
这样的代码下,如果我们不加上fork的话,我们最后实现的是什么呢?
在这里插入图片描述
实现出来是这样的,如果我们不是指向显示器的情况呢?反而是指向文件的重定向操作呢?
在这里插入图片描述
这样的结果反而是这样的,那如果说,我们加上fork这样的创造出来的子进程的话,又会是什么样子呢?
在这里插入图片描述
出现的反而是这个样子。这究竟是怎么一回事呢?答案就是问题出现在缓冲区刷新的定义不同导致的。 对于显示器来说,是一行的刷新,但是对于文件来说是全缓冲的刷新方式。利用了重定向,也就导致了刷新策略的不同,这样的话就导致了结果的不一样。还有就是可以看出区别就是,打印两遍的几乎都是库函数,只有系统调用的才打了一次。
知道不一样了之后再来细致的分析一下。其实对于fork来说,复制的是父进程的几乎所有的信息,所以在对于重定向到文件中的可运行程序来说,调用C语言实现的文件操作还没有刷新到OS中的缓冲区,还是在语言层面上的缓冲区中,所以对于子进程来说还会复制其中存留的消息,所以在最后fork完了结束之后的时候,才会显示出两遍的C语言函数的打印。

3、2、缓冲区代码形式展示

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

简单截图一下,这就是我们C语言中的FILE结构体,其中也包含之前所讲到的_fileno的标志符号。中间的一大部分也是为了维护语言级别的缓冲区而存在的大量的定义。这样的话,我就能够实现C语言对于库函数调用然后实现数据的格式化形式再交给系统,让系统进行操作下面的后续问题。

4、深化和实践利用

4、1、在shell中加入重定向

实现重定向,就需要我们能够读取得到重定向的方式,在此之前的shell中我们能够读取到我们用户的输入的指令。想要读到重定向的话也就特别简单,因为重定向的操作符也就只有三个,所以遍历一遍的话也就能够找到重定向的操作符了。当然了,找到重定向的操作符之后,需要我们去寻找后面的文件名,此时也需要注意,跳过合适的空格,找到真正的文件名称。类似于我们的那个之前shell中就有的寻找cwd名字时候的宏函数操作,这里的宏函数的优点也是显而易见的,1、能够直接使用函数内临时变量不需要进行传址操作,更能够让人读懂。2、宏函数在处理的时候会直接替换,这样的话能够减少变量创建,缩短一点时间。

void CheckRedir(char cmd[])
{
    // > >> <
    // "ls -a -l -n >  myfile.txt"
    int pos = 0;
    int end = strlen(cmd);

    while(pos < end)
    {
        if(cmd[pos] == '>')
        {
            if(cmd[pos+1] == '>')
            {
                cmd[pos++] = 0;
                pos++;
                redir_type = App_Redir;
                SkipSpace(cmd, pos);
                filename = cmd + pos;
            }
            else
            {
                cmd[pos++] = 0;
                redir_type = Out_Redir;
                SkipSpace(cmd, pos);
                filename = cmd + pos;
            }
        }
        else if(cmd[pos] == '<')
        {
            cmd[pos++] = 0;
            redir_type = In_Redir;
            SkipSpace(cmd, pos);
            filename = cmd + pos;
        }
        else
        {
            pos++;
        }
    }
}

这样的操作就是找到重定向符号的种类,同时确定重定向后面的文件的名字,能够帮助我们找到对应的文件。这里我们在找到符号之后就把那个位置设置为0,是因为在后一步的SplitCommand中,需要找到的结尾也是和0相同的ASCII码的值,这样能够稍微写的优雅一点。
还需要修改的地方就是执行我们命令的时候。

void ExecuteCommand()
{
    pid_t id = fork();
    if(id < 0) Die();
    else if(id == 0)
    {
        //重定向设置
        if(filename != NULL){
            if(redir_type == In_Redir)
            {
                int fd = open(filename, O_RDONLY);
                dup2(fd, 0);
            }
            else if(redir_type == Out_Redir)
            {
                int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
                dup2(fd, 1);
            }
            else if(redir_type == App_Redir)
            {
                int fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0666);
                dup2(fd, 1);
            }
            else
            {}
        }

        // child
        execvp(gArgv[0], gArgv);
        exit(errno);
    }
    else
    {
        // fahter
        int status = 0;
        pid_t rid = waitpid(id, &status, 0);
        if(rid > 0)
        {
            lastcode = WEXITSTATUS(status);
            if(lastcode != 0) printf("%s:%s:%d\n", gArgv[0], strerror(lastcode), lastcode);
        }
    }
}

需要进行重定向的设置,通过调用dup2的系统调用,实现我们上层能够看到的文件的重定向的操作,关于dup2的函数的参数的设置,还有功能,已经在刚刚讲过了,可以回头看看复习一下。
这样的话,我们就能够通过自己实现的shell实现读取操作,也能够实现重定向操作了。

4、2、简单实现库的封装

这一步的简单说明主要还是介绍,缓冲区的设置和定义的,并没有别的需求上的条件。所以主要关注缓冲区在其中的意义就行了。
实现库的封装实际上是挺难的,所以为了防止这么多了的情况下,还要讲不少的内容。所以期待下一篇吧!

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

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

相关文章

Axios基本语法和前后端交互

Axios是一个js框架&#xff0c;用于发送ajax请求。 一、导入 // node中&#xff0c;使用npm安装 npm install axios // HTML中&#xff0c;使用cdn安装 <script src"https://unpkg.com/axios/dist/axios.min.js"></script> 二、基本使用 // 使用axios…

MTK平台--蓝牙驱动数据加载的过程

前言: 先看这张图可以知道架构 LinuxKernel层: bluez协议栈、uart驱动, h4协议, hci,l2cap, sco, rfcomm Library层: libbluedroid.so 等 Framework层: 实现了Headset /Handsfree 和 A2DP/AVRCP profile,但其实现方式不同Handset/Handfree是直接 在bluez的RFCOMM So…

imagen: 具有深度语言理解的逼真的文本到图像扩散模型

1. 项目主页 Imagen: Text-to-Image Diffusion Models 我们推出了 Imagen&#xff0c;这是一种文本到图像的扩散模型&#xff0c;具有前所未有的照片级真实感和深层次的语言理解能力。Imagen 建立在大型 Transformer 语言模型在文本理解方面的强大功能之上&#xff0c;并依赖于…

JVM 调优篇7 调优案例2-元空间的优化解决

一 元空间 1.1 功能概述 方法区&#xff08;Method Area&#xff09;与 Java 堆一样&#xff0c;是各个线程共享的内存区域&#xff0c;它用于存储已被虚拟机加载的类信息、常量、即时编译器编译后的代码等数据。虽然Java 虚拟机规范把方法区描述为堆的一个逻辑部分&#xf…

数据结构与算法-18算法专向(hash)

话题引入&#xff1a; 给你N&#xff08;1<N<10&#xff09;个自然数,每个数的范围为&#xff08;1~10000000000&#xff09;。现在让你以最快的速度判断某一个数是否在这N个数内&#xff0c;不得使用已经封装好的类&#xff0c;该如何实现。 A[] new int[N1]&#xff…

快来尝尝,超赞的食家巷一窝丝

一窝丝&#xff0c;这个名字听起来就充满了诗意和神秘。当你第一次见到它时&#xff0c;定会被它那精致的外形所吸引。纤细如丝&#xff0c;盘绕在一起&#xff0c;宛如一个精美的艺术品。那丝丝缕缕&#xff0c;散发着淡淡的麦香味&#xff0c;仿佛在诉说着古老的故事。 制作食…

解读 Java 经典巨著《Effective Java》90条编程法则,第5条:优先考虑依赖注入来引用资源

【前言】欢迎订阅【解读《Effective Java》】系列专栏 《Effective Java》是 Java 开发领域的经典著作&#xff0c;作者 Joshua Bloch 以丰富的经验和深入的知识&#xff0c;全面探讨了 Java 编程中的最佳实践。这本书被公认为 Java 开发者的必读经典&#xff0c;对提升编码技…

Java 中常用的排序算法

Java 中常用的排序算法有很多&#xff0c;每种算法的时间复杂度和适用场景都不同。以下是几种常见的排序算法及其 Java 实现和讲解&#xff1a; 1. 冒泡排序 (Bubble Sort) 算法思路&#xff1a; 重复地遍历数组&#xff0c;每次比较相邻两个元素。如果前一个比后一个大&…

Web接入Sonic平台之安装

问题及解决方案 1.安装python的airtest-bdd依赖时报错&#xff0c;显示无法编译psutil note: This error originates from a subprocess, and is likely not a problem with pip. ERROR: Failed building wheel for psutil Failed to build psutil ERROR: ERROR: Failed to b…

【2025】基于 SpringBoot 的电影购票系统、电影购票系统、智能电影购票系统、电影购票平台、电影购票管理、微服务电影购票系统(源码+文档+讲解)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

传输层协议(TCP和UDP)

目录 一、UDP 1、UDPAPI 2、UDPAPI的使用 二、TCP 1、TCPAPI 2、TCP的相关特性 2.1 确认应答 2.2 超时重传 2.3 连接管理&#xff08;三次握手&#xff0c;四次挥手&#xff09; 2.4 滑动窗口 2.5 流量控制 2.6 拥塞控制 2.7 延时应答 2.8 捎带应答 2.9 面向字节…

【赵渝强老师】基于ZooKeeper实现Hadoop HA

由于在HA架构中包含的节点比较多&#xff0c;在进行实际部署的时候需要做好集群的规划。图14.9一共使用了4个节点来部署HDFS HA&#xff0c;它们分别是&#xff1a;bigdata112、bigdata113、bigdata114和bigdata115。由于Hadoop默认包含了HDFS和Yarn&#xff0c;因此在部署HDFS…

构建 LLM 应用程序时经常遇到的高级概念的快速指南

使用案例 数据支持的 LLM 应用程序有无数的用例&#xff0c;但大致可以分为四类&#xff1a; 结构化数据提取 Pydantic 提取器允许您指定要从数据中提取的精确数据结构&#xff0c;并使用 LLM 以类型安全的方式填充缺失的部分。这对于从 PDF、网站等非结构化来源中提取结构化…

阿里国际、eBay、乐天等跨境电商如何搭建测评系统给自己店铺测评

要实现自己养号给自己店铺进行测评&#xff0c;确实需要一系列周密的准备和规划&#xff0c;以确保整个过程既稳定安全又有效。以下是详细补充和强化建议&#xff1a; 1. 稳定的测评环境系统 选择高级防关联技术&#xff1a;除了使用国外的服务器、纯净的国外IP和防关联浏览器…

mysql怎样优化count(*) from 表名 where …… or ……这种慢sql

一 问题描述 线上发现一条类似这样的慢sql&#xff08;查询时长8s&#xff09;&#xff1a; select id,name,(select count(*) from t14 where t14.idt15.id or t14.id2t15.id) as cnt from t15 ; t14的id和id2字段上都有索引&#xff0c;但是因为条件里有or&#xff0c;导致…

Kubernetes调度基础

一、RC 和 RS 1. Replication Controller Replication Controller&#xff0c;简称 RC&#xff0c;复制控制器&#xff0c;可确保Pod 副本数达到期望值&#xff0c;也就是 RC 可确保一个 Pod 总是可用&#xff0c;或一组 Pod 的数量永远处于一个定值。 如果存在的 Pod 大于设…

杭州等保测评揭秘:数据安全如何成为企业的“一道锁”

在数字化时代&#xff0c;数据安全已成为企业和机构面临的重要挑战。杭州作为科技创新的前沿城市&#xff0c;积极推进信息安全建设&#xff0c;其中等保测评&#xff08;等级保护测评&#xff09;成为保障数据安全的重要手段。 等保测评是依据《信息安全等级保护管理办法》对…

代码随想录训练营第36天|二维背包

1049. 最后一块石头的重量 II class Solution { public:int lastStoneWeightII(vector<int>& stones) {int sumaccumulate(stones.begin(),stones.end(),0);int targetsum/2;vector<int> dp(target1,0);for(auto& stone: stones){for(int itarget; i>s…

如何快速学习拼音打字?

拼音打字是很多人学会使用电脑或手机的第一步&#xff0c;尤其是对于需要经常输入中文的人来说&#xff0c;熟练掌握拼音打字可以大大提升效率。下面分享一些快速学习拼音打字的方法和技巧&#xff0c;帮助你尽快掌握这项技能。 1. 了解拼音的基本规则 学习拼音打字之前&…

代码随想录算法训练营第五十八天 | 拓扑排序精讲-软件构建

目录 软件构建 思路 拓扑排序的背景 拓扑排序的思路 模拟过程 判断有环 写代码 方法一&#xff1a; 拓扑排序 软件构建 题目链接&#xff1a;卡码网&#xff1a;117. 软件构建 文章讲解&#xff1a;代码随想录 某个大型软件项目的构建系统拥有 N 个文件&#xff0c;文…