【Linux基础IO篇】用户缓冲区、文件系统、以及软硬链接

【Linux基础IO篇】用户缓冲区、文件系统、以及软硬链接

目录

  • 【Linux基础IO篇】用户缓冲区、文件系统、以及软硬链接
      • 深入理解用户缓冲区
        • 缓冲区刷新问题
        • 缓冲区存在的意义
      • File
        • 模拟实现C语言中文件标准库
      • 文件系统
        • 认识磁盘
        • 对目录的理解
      • 软硬链接
        • 软硬链接的删除
        • 文件的三个时间

作者:爱写代码的刚子

时间:2023.11.5

前言:本篇博客将介绍缓冲区、磁盘的构成、分区,以及文件系统中的结构、软硬链接

深入理解用户缓冲区

观察几个现象:

正常现象一:

在这里插入图片描述

现象二:

在这里插入图片描述

现象三:

在这里插入图片描述

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

解释现象

  1. 对于现象二:C语言文件操作函数中的字符串不带有’\n’,即数据还停留在C语言的缓冲区中,并未刷新和调用write()函数,将数据刷新到内核系统文件的缓冲区中,而write()函数由于是系统调用函数,能正常执行,但是由于close()函数将显示器文件关闭了,即使进程结束也不能将数据从缓冲区刷新到显示器中。(如果将close函数屏蔽,将会将C语言缓冲区中的数据刷新到显示器)

  2. 对于现象三:(1)在程序未进行重定向之前,默认是将数据写入显示器中,当遇到’\n’时,将数据从C语言的缓冲区中刷新到内核文件系统的缓冲区,fork()并不影响原本程序的运行。(2)在程序进行重定向之后,数据从向显示器写入变为了向文件中写入,缓冲区从行缓冲变为了全缓冲,所以此时的’\n’并不起作用,所以数据依然存储在C语言的缓冲区中,fork()函数创建子进程时子进程会将父进程的C语言缓冲区进行拷贝,当父子进程结束后将缓冲区里面的内容全部刷新,输出到显示器中。

  • 显示器的文件的刷新方案是行刷新,所以在printf执行完就会在遇到’\n’的时候会立即进行刷新,用户刷新的本质就是将数据通过1+write写入到内核中。(目前我们认为,只要将数据刷新到了内核,数据就可以到硬件了)。
缓冲区刷新问题
  1. 无缓冲 ——直接刷新
  2. 行缓冲——不刷新,碰到’\n’刷新(显示器)
  3. 全缓冲——缓冲区满了才刷新(普通文件的写入)
  4. 进程退出的时候也会刷新缓冲区
缓冲区存在的意义
  1. 解决效率问题
  2. 配合格式化(printf中需要将%d等符号进行替换)

File

FILE里面含有对应打开文件等缓冲区字段和维护信息,同时FILE对象属于用户,这个缓冲区属于用户级缓冲区(语言属于用户层)

模拟实现C语言中文件标准库
  • Mystdio.h文件:
#ifndef __MYSTDIO_H__
#define __MYSTDIO_H__
//open头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//
#include <unistd.h>
//
#include <string.h>
#include <stdlib.h>

#define FILE_MODE 0666
#define SIZE 1024

#define FLUSH_NOW 1//0001
#define FLUSH_LINE 2//0010
#define FLUSH_ALL 4//0100

typedef struct IO_FILE{
    int fileno;
    int flag;
    char inbuffer[SIZE];
    int in_pos;
    char outbuffer[SIZE];
    int out_pos;//缓冲区的有效字符和无效字符分界
}_FILE;

_FILE* _fopen(const char* filename,const char* flag);
int _fwrite(_FILE *fp,const char*s,int len);
void _fclose(_FILE *fp);

#endif
  • Mystdio.c文件:
#include "Mystdio.h"

_FILE* _fopen(const char* filename,const char* flag)
{
    int f=0;
    int fd=-1;
    if(strcmp(flag,"w")==0)
    {
        f=O_CREAT|O_WRONLY|O_TRUNC;
        fd= open(filename,f,FILE_MODE);
    }
    else if(strcmp(flag,"r")==0)
    {
        f=O_CREAT|O_RDONLY|O_TRUNC;
        fd= open(filename,f,FILE_MODE);
    }
    else if(strcmp(flag,"a")==0)
    {
        f=O_APPEND;
        fd= open(filename,f);
    }
    else
    {
        return NULL;
    }
    
    if(fd==-1) return NULL;
    //创建文件结构对象
    _FILE* fp=(_FILE*)malloc(sizeof(_FILE));
    if(fp==NULL)return  NULL;

    fp->fileno = fd;
    fp->flag= FLUSH_LINE;
    fp->out_pos=0;


    return fp;
}
int _fwrite(_FILE *fp,const char*s,int len)
{
    memcpy(&fp->outbuffer[fp->out_pos],s,len);//这里省略了异常处理
    fp->out_pos+=len;

    if(fp->flag & FLUSH_NOW)
    {
        write(fp->fileno,fp->outbuffer,fp->out_pos);
        fp->out_pos=0;
    }
    else if(fp->flag & FLUSH_LINE)
    {
        if(fp->outbuffer[fp->out_pos-1]=='\n')//'\n'可能出现在字符中间,这时候需要对字符串做裁剪
        {
            write(fp->fileno,fp->outbuffer,fp->out_pos);
            fp->out_pos=0;
        }
    }
    else if(fp->flag & FLUSH_ALL)
    {
        if(fp->out_pos==SIZE)
        {
            write(fp->fileno,fp->outbuffer,fp->out_pos);//全写出去
            fp->out_pos=0;
        }
       
    }
    return len;//成功写入的长度
}
void _fflush(_FILE *fp)
{
    if(fp->out_pos>0)
    {
        write(fp->fileno,fp->outbuffer,fp->out_pos);
        fp->out_pos=0;
    }
}
void _fclose(_FILE *fp)
{
    if(fp==NULL)return ;
    _fflush(fp);
    close(fp->fileno);
    free(fp);
}

Main.c文件:

#include "Mystdio.h"

#define myfile "test.txt"
int main()
{
    _FILE* fp=_fopen(myfile,"w");
    if(fp==NULL)
    {
        return 1;
    }
    int cnt =10;
    while(cnt--)
    {
        const char* msage = "hello Linux\n";
        _fwrite(fp,msage,strlen(msage));
        sleep(1);

    }
    //_fflush(fp)
    return 0;
}

测试

makefile文件:

在这里插入图片描述

while :;do cat test.txt;sleep 1;echo “----------------------”;done持续打印文件内容

在这里插入图片描述

一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲。 printf fwrite 库函数会自带缓冲区(进度条例子就可以说明),当发生重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲。而我们放在缓冲区中的数据,就不会被立即刷新,甚至fork之后 但是进程退出之后,会统一刷新,写入文件当中。 但是fork的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的 一份数据,随即产生两份数据。write没有变化,说明没有所谓的缓冲。

printf fwrite 库函数会自带缓冲区(用户级缓冲区),而 write系统调用没有带缓冲区。(为了提升整机性能,OS也会提供相关内核级缓冲区)

文件系统

认识磁盘

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 磁头是一面一个,磁头和盘面不接触,磁头臂会进行摆动来定位柱面或磁道(磁臂运动越少,效率越高,反之越低),所以在软件设计上一定要有意识将相关数据放在一起

磁盘的逻辑结构是线性的(对磁盘理解和建模)

在这里插入图片描述

  • 扇区的一般大小是512字节或者4kb

不仅CPU有寄存器,其他设备(外设)也存在寄存器

在这里插入图片描述

对磁盘进行分区

在这里插入图片描述

关于inode中的block数组:

inode中有struct inode结构体,里面包括了文件所有的属性,和一个blocks[15]数组,其中的下标[0, 11]直接保存的就是该文件对应的blocks编号,下标[12, 15]指向一个datablock,但是这个datablock不保存有效数据,而保存文件所适用的其它块的编号。(相当于一个二级索引)

stat +文件名查看文件的具体信息

在这里插入图片描述

ls -lia查看所有文件的信息(包括文件的inode)

ls -i查看当前目录下各文件的inode编号

在这里插入图片描述

启动块的大小是确定的,而块组的大小是由格式化的时候确定的,并且不可以更改。
文件 = 内容 + 属性,二者都是数据,都要存储。Linux采用的是将内容和属性数据分开存储的方案,内容在block中(4KB),内容是可以无限增多的。属性数据在inode中(128字节),文件的属性是稳定的。

注意一个要点,inode可能会存在用完的情况

  • Linux系统中,一个文件一个inode,每一个inode。每一个inode都有自己的inode编号(inode的设置是以分区为单位的,不能跨分区)
对目录的理解

Linux下一切皆文件,目录也是一个文件,通过文件名(对应的inode编号)-> 找到自己所处的目录 -> 根据目录的inode,找到目录的data block -> 将文件名和inode编号的映射关系写入到目录的数据块中。

在这里插入图片描述

在这里插入图片描述

  • 问题1:为什么同一个目录下不能存在同名文件?

因为一个文件只存在一个inode,文件名是作为key值去找inode的,如果存在同名文件就会破坏对应的映射关系。

  • 问题2:为什么没有w权限就不能创建文件?

即便是能创建文件,也不能将该文件与inode的映射关系写到数据块中。

  • 问题3:为什么没有r权限就不能查看文件?

无法拿到该目录文件中文件与inode之间的映射关系

  • 问题4:为什么没有x权限就不能进入目录?

不让用户更改环境变量中的目录信息

查找任何一个文件时,我们必须从当前目录递归到根目录,然后从根目录信息中查找对应子目录的inode信息(效率会低)

所以Linux中会存在提升效率的方法,将常用的路径信息进行缓存(dentry缓存,里面的结构算法较复杂)

软硬链接

建立软链接

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

软链接的inode不同

软连接又叫符号链接,软连接文件相当于源文件来说是一个独立的文件,该文件有自己的inode号,但是该文件只包含了源文件的路径名,所以软连接文件的大小要比源文件小得多。软连接就类似于Windows操作系统当中的快捷方式。软链接保存的是对应文件的所在路径

ln -s 对应的路径 软链接的名字添加快捷方式

建立硬链接

在这里插入图片描述

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

硬链接的inode相同,同时文件的引用计数变为了2

  • 硬连接数本质就是该文件inode属性中的计数器count,标识有几个文件名和我的inode建立了映射关系。简言之,就是有几个文件名指向我的inode(文件本身)硬链接就是让多个不在或者同在一个目录下的文件名,同时能够修改同一个文件,其中一个修改后,所有与其有硬链接的文件都一起修改了。

为什么文件被创建出来,默认的硬连接数是1?

  • 如果硬链接数是0,那么就应该是被关闭的文件了,所以至少应该从1开始。此外,普通文件的文件名,本身就和自己的inode具有映射关系,且只有1个,所以文件的默认硬连接数是1。

创建一个新目录时引用计数默认为2

在这里插入图片描述

在这里插入图片描述

  • 我们也可以根据系统的硬连接数,不进入文件,从而估算出文件的目录数(一个目录下相邻的子目录数 = 该目录的硬连接数 - 2)。因此,硬链接的一个作用就是进行路径切换
软硬链接的删除

unlink(unlink也可以删除普通文件,与rm没什么区别)

在这里插入图片描述

文件的三个时间

在这里插入图片描述

这其中包含了文件的三个时间信息:

  • Access: 文件最后被访问的时间。
  • Modify: 文件内容最后的修改时间。
  • Change: 文件属性最后的修改时间。

当我们修改文件内容时,文件的大小一般会随之改变,所以Modify的改变会带动Change一起改变,但对该文件属性一般不会影响文件内容,所以一般情况下Change的改变不会带动Modify的改变。此外,我们可以使用touch命令把这三个时间都更新到最新状态。(当一文件存在时使用touch命令,此时touch命令的作用变为更新文件信息)。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Excel】函数sumif范围中符合指定条件的值求和

SUMIF函数是Excel常用函数。使用 SUMIF 函数可以对报表范围中符合指定条件的值求和。 Excel中sumif函数的用法是根据指定条件对若干单元格、区域或引用求和。 sumif函数语法是&#xff1a;SUMIF(range&#xff0c;criteria&#xff0c;sum_range) sumif函数的参数如下&#xff…

安徽首届道医传承十八绝技发布会在合肥成功举办

近日&#xff0c;在安徽合肥举行了首届道医传承十八绝技发布会&#xff0c;本次会议由安徽渡罗门生物科技有限公司、北京道武易医文化传播有限公司、楼观台道医文化研究院联合举办。现场吸引了来自全国各地民族医学领域的专家学者参与讨论与交流。本次会议旨在促进道医的交流与…

OCR技术狂潮:揭秘最新发展现状,引爆未来智能时代

OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;技术自20世纪以来经历了长足的发展&#xff0c;随着计算机视觉、人工智能和深度学习等领域的进步&#xff0c;OCR技术在准确性、速度和适用范围上都取得了显著的进展。以下是OCR技术发展的现…

在gitlab中指定自定义 CI/CD 配置文件

文章目录 1. 介绍2. 配置操作3. 配置场景3.1 CI/CD 配置文件在当前项目step1&#xff1a;在当前项目中创建目录&#xff0c;编写流水线文件存放在该目录中step2&#xff1a;在当前项目中配置step3&#xff1a;运行流水线测试 3.2 CI/CD 配置文件位于外部站点上step1&#xff1a…

嵌入式养成计划-47----QT--基于QT的OpenCV库实现人脸识别功能

一百二十一、基于QT的OpenCV库实现人脸识别功能 121.1 UI 界面 登录按钮现在没啥实际作用&#xff0c;因为没加功能&#xff0c;可以添加在识别成功后运行的功能代码 121.2 思路 显示人脸&#xff1a; 通过 VideoCapture 这个类下面的 open() 方法打开摄像头&#xff0c;对…

进口猫罐头在排行榜中是否靠前?排行榜中靠前的猫罐头测评

养猫这6年&#xff0c;我对猫咪的日常饮食把关一直很严格。这些年我给我家猫们购买过很多不同品牌、不同口味的罐头&#xff0c;在猫罐头的挑选、分析上还是有一些经验的。今天&#xff0c;我将和大家一起探讨进口猫罐头在排行榜中是否靠前&#xff1f;同时&#xff0c;我将为大…

优化VMD全家桶!

↖加关注这种话银家怎么好意思说出口嘛-- 声明&#xff1a;对于作者的原创代码&#xff0c;禁止转售倒卖&#xff0c;违者必究&#xff01; 本期对以往智能算法优化VMD的代码做一个总结。 代码目录 优化VMD全家桶&#xff01;&#xff1a;https://mbd.pub/o/bread/ZZaVlp5xVMD为…

SAP CK51N销售订单取关联采购订单价格增强

需求fs 销售订单及行项目 enhancement 测试

微服务-我对Spring Clound的理解

官网&#xff1a;https://spring.io/projects/spring-cloud 官方说法&#xff1a;Spring Cloud 为开发人员提供了快速构建分布式系统中一些常见模式的工具&#xff08;例如配置管理、服务发现、熔断器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话…

什么是Node.js的调试器(debugger)工具?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

力扣第1035题 不相交的线中等 c++ (最长公共子序列) 动态规划 附Java代码

题目 1035. 不相交的线 中等 相关标签 数组 动态规划 在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。 现在&#xff0c;可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线&#xff0c;这些直线需要同时满足满足&#xff1a; nums1[i] nums2[j]…

uni-app前端H5页面底部内容被tabbar遮挡

问题&#xff1a; 在用uniapp写小程序的时候&#xff0c;底部有一部分内容没显示出来&#xff0c;被底部的tabbar遮挡住了 解决&#xff1a; 给最外部的view设置样式padding-bottom: var(--window-bottom)&#xff0c;如下 参考&#xff1a; 参考1 参考2 使用 uni-app 框…

idea Plugins 搜索不到插件

Settings — System Settings — HTTP Proxy&#xff0c;打开HTTP Proxy 页面&#xff0c;设置自动发现代理&#xff1a; 勾选Atuto-detect proxy settings&#xff0c;勾选Automatic proxy configuration URL&#xff0c;输入&#xff1a; https://plugins.jetbrains.com/id…

Julia绘图初步:Plots

文章目录 基础绘图绘图类型点线参数三维绘图 Julia开发环境 基础绘图 Julia中最常用的绘图模块自然是Plots&#xff0c;点击]进入安装模式后&#xff0c;输入add Plots即可安装&#xff0c;装完之后按下退格键回到Julia环境&#xff0c;就可以调用了 using Plots x 0:0.1:1…

【2023-11-09】git使用随记——gitignore文件配置某些文件忽略

git使用随记——gitignore文件配置某些文件忽略 通过git进行版本控制在项目中是非常常见的&#xff0c;一些项目构建上的文件通常是不需要进行版本控制的&#xff0c;也就无需推送到git仓库中&#xff0c;比如前端项目中的node_module目录。提供配置.gitignore文件 但是某些情…

Android Studio代码无法自动补全

Android Studio代码自动无法补全问题解决 在写layout布局文件时&#xff0c;代码不提示&#xff0c;不自动补全&#xff0c;可以采用如下方法&#xff1a; 点击File—>Project Structure&#xff0c;之后如图所示&#xff0c;找到左侧Modules&#xff0c;修改SDK版本号&…

Python基础教程之十九:Python优先级队列示例

1.什么是优先队列 优先级队列是一种抽象数据类型&#xff0c;类似于常规队列或堆栈数据结构&#xff0c;但每个元素还具有与之关联的“优先级”。在优先级队列中&#xff0c;优先级高的元素先于优先级低的元素提供。如果两个元素具有相同的优先级&#xff0c;则将根据其在队列…

【C语言 | 预处理】C语言预处理详解(一) —— #define、#under、#if、#else、#elif、#endif、#include、#error

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

mac M2 pytorch_geometric安装

我目前的环境是mac M2&#xff0c;我在base环境中安装了pytorch_geometric,仅仅做测试用的&#xff0c;不做真正跑代码的测试 首先我的base环境的设置如下&#xff1a; pip install pyg_lib torch_scatter torch_sparse torch_cluster torch_spline_conv -f https://data.pyg.…

Tomcat隐藏版本号和关闭默认管理页面

一. 隐藏Tomcat异常页面中的版本信息&#xff0c;Tomcat服务器版本号泄露 Tomcat/8.5.xx相关版本号等信息&#xff0c;是不安全的。这会被黑客获取到&#xff0c;利用该版本的其他漏洞对服务器进行异常操作&#xff0c;所以需要隐藏掉。 进入tomcat安装目录 apache-tomcat-8.…