【Linux】理解Linux中一切皆文件、缓冲区、ext2文件系统、软硬链接

news2025/1/24 13:21:22
头像
⭐️个人主页:@小羊
⭐️所属专栏:Linux
很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~

动图描述

目录

  • 1、如何理解在Linux中一切皆文件?
    • 1.1 概述
    • 1.2 文件类型
    • 1.3 优势
  • 2、缓冲区
    • 2.1 为什么要引入缓冲区?
    • 2.2 缓冲类型
  • 3、Ext系列文件系统
  • 4、软硬链接


1、如何理解在Linux中一切皆文件?

1.1 概述

在windows中是文件的东西,在linux中也是文件;其次一些在windows中不是文件的东西,比如进程、磁盘、显示器、键盘这样硬件设备也被抽象成了文件,你可以使用访问文件的方法访问它们获得信息;甚至管道,也是文件;将来我们要学习网络编程中的socket(套接字)这样的东西,使用的接口跟文件接口也是一致的。


1.2 文件类型

  1. 普通文件:这是最常见的文件类型,如文本文件、二进制文件、图像文件等。它们存储着数据或程序代码。
  2. 目录文件:目录在Linux中也被视为一种特殊的文件,它包含了目录内各个文件的文件名和指向这些文件的指针。通过访问目录文件,可以浏览和管理目录内的文件。
  3. 设备文件:设备文件代表了系统中的硬件设备,如硬盘、打印机、网络接口等。通过对设备文件的读写操作,可以实现对硬件设备的控制。设备文件通常位于/dev目录下。
  4. 套接字(Socket):套接字是一种特殊的文件,用于网络通信。在Linux中,每个套接字都有一个对应的文件描述符,通过读写这个文件描述符可以实现网络通信。
  5. 管道(Pipe):管道也是一种特殊的文件,用于进程间通信。它将一个进程的输出作为另一个进程的输入,实现了进程间的数据传递。

1.3 优势

  1. 统一接口:“一切皆文件”使得Linux系统提供了一个统一的接口来访问和管理所有资源。这降低了系统的复杂性,并提高了系统的可扩展性。
  2. 简化编程:程序员只需要熟悉文件系统的接口,就可以实现对系统资源的操作和管理。这降低了编程难度,提高了开发效率。
  3. 资源抽象:通过将所有资源都抽象为文件的形式,Linux系统实现了对资源的统一管理和访问。这有助于实现资源的共享和保护,提高了系统的安全性和可靠性。

这样做最明显的好处是,开发者仅需要使用一套API和开发工具,即可调取Linux系统中绝大部分的资源。举个简单的例子,Linux中几乎所有读(读文件,读系统状态,读PIPE)的操作都可以用read函数来进行;几乎所有更改(更改文件,更改系统参数,写PIPE)的操作都可以用write函数来进行。

在这里插入图片描述


2、缓冲区

2.1 为什么要引入缓冲区?

缓冲区是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。

  • 引入缓冲区是为了减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。

  • 调用系统调用,是有成本的,所以有个用户级缓冲区。

  • 内核级缓冲区何时刷新是由OS自主决定的,如果我们想要自己控制也是有办法的,有系统调用fsync,强制刷新。

  • 当一个进程在退出的时候,会自动刷新自己的缓冲区,fclose关闭文件的时候也会自动刷新。

  • 我们用printf等函数,首先写入到用户级缓冲区中,可以通过fflush刷新到内核级缓冲区。用户级缓冲区的作用是减少系统调用次数,内核级缓冲区的作用是减少IO次数。


2.2 缓冲类型

标准I/O提供了3种类型的缓冲区。

  • 全缓冲区:这种缓冲方式要求填满整个缓冲区后才进行IO系统调用操作。对于磁盘文件的操作通常使用全缓冲的方式访问。
  • 行缓冲区:在行缓冲情况下,当在输入和输出中遇到换行符时,标准I/O库函数将会执行系统调用操作。当所操作的流涉及一个终端时(例如标准输入和标准出),使用行缓冲方式。因为标准I/O库每行的缓冲区长度是固定的,所以只要填满了缓冲区,即使还没有遇到换行符,也会执行I/O系统调用操作,默认行缓冲区的大小为1024
  • 无缓冲区:无缓冲区是指标准I/O库不对字符进行缓存,直接调用系统调用。标准出错流stderr通常是不带缓冲区的,这使得出错信息能够尽快地显示出来。

除了上述列举的默认刷新方式,下列特殊情况也会引发缓冲区的刷新:

  1. 缓冲区满时;
  2. 执行flush语句;

通过下面这个例子来理解一下缓冲区的刷新:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
	//c库函数
	printf("hell printf\n");
	fprintf(stdout, "hello fprintf\n");
	const char *str = "hello fwrite\n";
	fwrite(str, 1, strlen(str), stdout);

	//系统调用
	const char *w = "hello write\n";
	write(1, w, strlen(w));

	return 0;
}

在这里插入图片描述
当我们往显示器上写入时是行刷新,打印顺序和我们代码一致,如果将往显示器上写入重定向到往文件中写入,就不是行刷新了,而是缓冲区满了才刷新,所以最后先刷新了系统调用write,最后进程结束的时候再自动刷新的用户级缓冲区

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
	//c库函数
	printf("hell printf\n");
	fprintf(stdout, "hello fprintf\n");
	const char *str = "hello fwrite\n";
	fwrite(str, 1, strlen(str), stdout);

	//系统调用
	const char *w = "hello write\n";
	write(1, w, strlen(w));

	//子进程
	fork();
	
	return 0;
}

在这里插入图片描述
如果我们在最后创建一个子进程,对于往显示器上写入时的行刷新不影响,不过将往显示器上写入重定向到往文件中写入时就和上面不一样了,因为C库函数先将字符串写入到用户级缓冲区中,最后父子进程各自把它们的缓冲区刷新了一遍,所以就有了两份数据,而系统调用write写入到用户级缓冲区后自己就将数据拷贝到内核级缓冲区了,不等到进程结束再刷新。

我们自己封装一个简单的stdio.h,来深刻理解一下数据写入的过程:

#pragma once 

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>

#define SIZE 1024

#define FLUSH_NONE 0
#define FLUSH_LINE 1
#define FLUSH_FULL 2

struct IO_FILE
{
	int flag; // 刷新方式
	int fileno; //文件描述符
	char outbuffer[SIZE];
	int size;
	int capacity;
};

typedef struct IO_FILE mFILE;

mFILE *mfopen(const char *filename, const char *mode);
int mfwrite(const void *ptr, int num, mFILE *stream);
void mfflush(mFILE *stream);
void mfclose(mFILE *stream);
#include "mystdio.h"

mFILE *mfopen(const char *filename, const char *mode)
{
    int fd = -1;
	if (strcmp(mode, "r") == 0)
	{
		fd = open(filename, O_RDONLY);
	}
	else if (strcmp(mode, "w") == 0)
	{
		fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
	}
	else if (strcmp(mode, "a") == 0)
	{
		fd = open(filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
	}
	if (fd < 0)
	{
		return NULL;
	}
	mFILE *mf = (mFILE*)malloc(sizeof(mFILE));
	if (mf == NULL)
	{
		close(fd);
		return NULL;
	}

	mf->flag = FLUSH_LINE;
	mf->fileno = fd;
	mf->size = 0;
	mf->capacity = SIZE;

	return mf;
}

void mfflush(mFILE *stream)
{
	if (stream->size > 0)
	{
		//刷新的本质
		write(stream->fileno, stream->outbuffer, stream->size);
		stream->size = 0;
	}
}

int mfwrite(const void *ptr, int num, mFILE *stream)
{
	//1、库函数写方法:将数据拷贝到缓冲区
	memcpy(stream->outbuffer+stream->size, ptr, num);
	stream->size += num;

	//2、检测是否刷新
	if (stream->flag == FLUSH_LINE && stream->size > 0 && stream->outbuffer[stream->size - 1] == '\n')
	{
		mfflush(stream);
	}
	return num;
}

void mfclose(mFILE *stream)
{
	if (stream->size > 0)
	{
		mfflush(stream);
	}
	close(stream->fileno);
}

3、Ext系列文件系统

文件有被打开的文件未打开的文件,前面我们介绍的都是被打开的文件,其实对于文件来说未打开的文件是占多数的,未打开的文件在磁盘上。
文件存在就要被访问,访问文件的前提是要打开文件,打开文件的前提是先要找到这个文件,那么对于未打开的文件我们如何找到它,就是文件管理系统需要做的工作。不管是内存中已打开的文件还是磁盘中未打开的文件,都要被文件系统管理起来。整个过程可以类比快递的管理系统。

我们需要讨论下面两个问题:

  1. 文件系统是怎么管理磁盘中未打开的文件的?
  2. 如何理解文件的路径?

扇区是磁盘存储数据的基本单位,通常是512KB,所以磁盘也叫块设备。磁盘就是一个元素为扇区的一维数组,数组的下标就是每一个扇区的LBA地址,OS使用磁盘,就可以用一个数字访问磁盘扇区。

在这里插入图片描述

  • 每个文件都有自己的inode,就像进程都有自己的PCB一样,inode是文件属性数据的集合,是一个结构体,特殊的是文件名属性不在inode中保存。Linux中,文件内容和文件属性是分开存储的。

  • 找一个文件,是通过inode编号找的。删除一个文件,只需要把inode BitmapBlock Bitmap中对应的比特位由1置0即可,所以删除一个文件后也是可以恢复的。

  • 文件系统以分区为单位,不同的分区可以是不同的文件系统。对于Super Block,一个分区内的多个组中一般只有几个组中存在,且都是一样的,这样做的目的为了备份,防止一整个分区都挂掉。

  • 格式化的本质是:向一个分区中写入文件系统。

  • 为了稳定,一个组里面inode个数,block个数都是固定的。inode以分区为单位,一个分区一套inodeinode分配的时候,只需要确定每个组的起始inodeblock也是统一编号的,和inode类似。

inodeblock是怎么映射的?

目录和普通文件类似,也有inodedatablock,其内容是文件名和inode的映射关系

文件的三个时间:

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

4、软硬链接

ln -s file.txt file-soft.link:给对应的文件建立软链接。
在这里插入图片描述

1、如何理解软硬链接?

  • 软链接有独立的inode,软链接内容保存的是目标文件的路径,就像Windows中的快捷方式。
  • 硬链接不是独立的文件,没有独立的inode,硬链接本质上就是一组文件名和已经存在的文件的映射关系。
  • Linux不允许对目录新建硬链接。

2、为什么要有软硬链接?

  • 软链接最大的作用就是以最简单的方式,快速定位一个文件或目录。
  • 硬链接可以做文件备份。
  • ...就是硬链接。

unlink删除软链接。


本篇文章的分享就到这里了,如果您觉得在本文有所收获,还请留下您的三连支持哦~

头像**博客之星2024年度总评选—主题文章创作要求:**

1、文章创作方向主要以总结盘点、技术总结或技术洞察三个方向为主( 3 选 1 ),具体如下:

  • 总结盘点类:个人成长与突破盘点、年度创作历程回顾、个人生活与博客事业的融合与平衡等;
  • 技术总结类:特定技术领域的年度深度总结、技术工具与平台的年度使用心得、技术项目实战经验与成果展示等;
  • 技术洞察类:前沿技术趋势洞察与分析、跨领域技术融合与创新实践、技术对社会与人文的影响深度思考等。

2、文章必须为公开且原创,严禁抄袭、洗稿、引流等违规行为;
3、投稿内容需积极向上,字数不低于 800 字(不包含代码);
4、未在规定时间内完成创作和未按照要求的创作均视为无效参与。

提醒:在发布作品前,请将不需要的内容删除。

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

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

相关文章

在Docker 容器中安装 Oracle 19c

在 Docker 容器中安装 Oracle 19c 是可行的&#xff0c;但它相较于其他数据库&#xff08;如 MySQL、PostgreSQL 等&#xff09;会复杂一些&#xff0c;因为 Oracle 数据库有一些特定的要求&#xff0c;如操作系统和库的依赖&#xff0c;以及许可证问题。 不过&#xff0c;Ora…

【数据库】详解MySQL数据库中的事务与锁

目录 1.数据库事务 1.1.事务的四大特性 1.2.事务开启的方式 1.3.读一致性问题及其解决 2.MVCC解决读一致性问题原理 2.1.MVCC概念 2.2.准备环境 3.MySQL中的锁 3.1.行锁之共享锁 3.2.行锁之排它锁 1.数据库事务 数据库事务&#xff08;Transaction&#xff09;是一种…

springboot 配置redis

环境配置 springboot3.4 redis5.0.14 redis准备参考下面文章 window下安装redis以及启动 redis客户端安装 引入依赖 <!-- 集成redis依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-…

EEG代码实践:diffusion EEG——扩散模型生成EEG信号

2024/1/22&#xff1a; 原始EEG信号的生成说实话一直做不到让人满意的水平&#xff0c;之前做的MIEEG复现也迟迟没有调整到自己想要的程度&#xff0c;与论文中的效果还是有些差距。改换思路使用离散小波变换&#xff0c;用变换之后的信号做生成任务则好了许多。从大二开始一直…

Banana Pi BPI-RV2 开发板矽昌通信 RISC-V路由芯片SF21H8898优势亮点

Banana Pi BPI-RV3开源路由器 1. 8898芯片具备强大的网络加速硬件性能&#xff0c;能够在小字节报文条件下实现高效数据转发&#xff1a;  单WAN口性能&#xff1a;支持 64 字节报文单向转发速率达到 2.5 Gbps&#xff0c;双向转发速率为 5 Gbps。双WAN口性能&#xff1a;支…

光谱相机在智能冰箱的应用原理与优势

食品新鲜度检测 详细可点击查看汇能感知团队实验报告&#xff1a;高光谱成像技术检测食物新鲜度 检测原理&#xff1a;不同新鲜程度的食品&#xff0c;其化学成分和结构会有所不同&#xff0c;在光谱下的反射、吸收等特性也存在差异。例如新鲜肉类和蔬菜中的水分、蛋白质、叶…

xxljob执行失败,xxl-job remoting error(sl.nts.com), for url : http://xxxxxxxxxx/run

问题 项目部署后&#xff0c;发现xxljob没有正常工作&#xff0c;报错 尝试解决&#xff1a; &#xff08;1&#xff09;检查xxljob配置&#xff08;无问题&#xff09; &#xff08;2&#xff09;检查服务器hosts文件域名配置&#xff08;依旧无问题&#xff09; 各种能检查…

什么是全息展示

全息展示。这一术语来源于“全息图”&#xff08;Holography&#xff09;的概念&#xff0c;而“全息图”这个词是由希腊词根 "holos" 演变而来&#xff0c;意为“整体的”或“完整的”。全息技术的核心在于它能够捕捉并再现物体的所有光学信息——不仅仅是强度&…

服务器内部是如何运行的

服务器内部的运行可以从硬件和软件两个方面来解释。 一、硬件层面 服务器的硬件与普通计算机相似,但它通常具有更高的性能和更强的扩展性。服务器硬件包括: 1.中央处理单元(CPU):负责执行服务器上的计算任务。服务器一般配备多核心的高性能CPU,以支持多个请求并行处理…

【Linux】文件操作、系统IO相关操作、inode和输入输出重定向

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1、理解文件1.1 狭义理解1.2 广义理解1.3 文件操作1.4 系统角度 2、系统文件IO2.1 文件相关操作2.2 文件描述符2.3 重定向 3、动静…

Jetson Xavier NX (ARM) 使用 PyTorch 安装 Open3D-ML 指南

由于 Jetson 为 ARM64 (aarch64) 的系统架构&#xff0c;所以不能用 pip install 直接安装&#xff0c;需要通过源码编译。 升级系统 JetPack 由于 Open3D-ML 目前只支持 CUDA 10.0 以及 CUDA 11.*&#xff0c;并且 JetPack 的 CUDA 开发环境只有10.2、11.4以及12.2&#xff0…

【Vim Masterclass 笔记25】S10L45:Vim 多窗口的常用操作方法及相关注意事项

文章目录 S10L45 Working with Multiple Windows1 水平分割窗口2 在水平分割的新窗口中显示其它文件内容3 垂直分割窗口4 窗口的关闭5 在同一窗口水平拆分出多个窗口6 关闭其余窗口7 让四个文件呈田字形排列8 光标在多窗口中的定位9 调节子窗口的尺寸大小10 变换子窗口的位置11…

《keras 3 内卷神经网络》

keras 3 内卷神经网络 作者&#xff1a;Aritra Roy Gosthipaty 创建日期&#xff1a;2021/07/25 最后修改时间&#xff1a;2021/07/25 描述&#xff1a;深入研究特定于位置和通道无关的“内卷”内核。 &#xff08;i&#xff09; 此示例使用 Keras 3 在 Colab 中查看 GitHub …

Linux 进程环境变量:深入理解与实践指南

&#x1f31f; 快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。&#x1f31f; &#x1f6a9;用通俗易懂且不失专业性的文字&#xff0c;讲解计算机领域那些看似枯燥的知识点&#x1f6a9; 在 Linux 系统里…

【博客之星】2024年度总结

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…

Linux下php8安装phpredis扩展的方法

Linux下php8安装phpredis扩展的方法 下载redis扩展执行安装编辑php.ini文件重启php-fpmphpinfo 查看 下载redis扩展 前提是已经安装好redis服务了 php-redis下载地址 https://github.com/phpredis/phpredis 执行命令 git clone https://github.com/phpredis/phpredis.git执行…

训练大模型所需要的内存计算

计算训练一个7B参数大模型所需的显存&#xff0c;主要涉及以下几个方面&#xff1a; 1. 模型参数 每个参数通常需要4字节&#xff08;32位浮点数&#xff09;&#xff0c;因此7B参数的显存需求为&#xff1a; 2. 优化器状态 常见的优化器如Adam&#xff0c;每个参数需要存…

笋瓜果实的代谢组学和转录组分析-文献精读103

Metabolomics and Transcription Profiling of Pumpkin Fruit Reveals Enhanced Bioactive Flavonoids and Coumarins in Giant Pumpkin (Cucurbita maxima) 笋瓜果实的代谢组学和转录组分析揭示了笋瓜&#xff08;Cucurbita maxima&#xff09;中生物活性黄酮和香豆素的增强 …

Jenkins下载 Maven、Allure 插件并且配置环境

文章目录 Jenkins在插件中心下载 maven、allure插件maven插件下载allure插件下载 配置maven、allure 往期推荐&#xff1a; 最新! 在 Linux上搭建Jenkins环境! Jenkins邮件通知的详细配置含邮件通知模板&#xff01; Jenkin配置企业微信通知 Jenkins在插件中心下载 maven、…

【深度学习】微积分

微积分 在2500年前&#xff0c;古希腊人把一个多边形分成三角形&#xff0c;并把它们的面积相加&#xff0c;才找到计算多边形面积的方法。 为了求出曲线形状&#xff08;比如圆&#xff09;的面积&#xff0c;古希腊人在这样的形状上刻内接多边形。 如图2.4.1所示&#xff0c…