【Linux】探索文件I/O奥秘,解锁软硬链接与生成动静态库知识

目录

1、C文件接口

1.1什么是当前路径?

1.2程序默认打开的文件流:

2、系统文件I/O

2.1.接口介绍:

2.1.1open:

参数讲解;

flags如何实现一个参数就可以有多个参数传参的效果?

open函数的返回值:

3.文件描述符fd

3.1 0 & 1 & 2

3.2进程怎么知道了打开哪些文件呢?

3.3文件描述符的分配规则&&利用规则实现重定向

fd的分配规则:

使用 dup2 系统调用

4.缓冲区问题

4.1c语言为什么要存在语言层面上的缓冲区?

4.2那什么时候开始刷新到系统当中的缓冲区呢?

4.3缓冲区在哪里呢?

4.4与fork函数的结合

5、关于磁盘等相关硬件知识

5.1、磁盘的机械构成

5.2、磁盘的物理存储

5.3、磁盘的逻辑存储

5.4文件系统

注意:

1、那我们的文件名在哪里呢?

2、重谈文件的增删改查:

6.软硬连接:

6.1、操作观察现象:

软连接:本质是一个文件,有独立的inode​编辑

硬连接:本质不是一个独立的文件,因为它的inode编号和目标文件相同!​编辑

6.2、软硬链接的原理

6.3、软硬链接的应用场景:

软链接:对应文件的删除

硬链接:

7、动静态库:

7.1基础认知

7.2为什么要有库:

7.3我们如何将目标文件进行打包形成一个库文件呢?

7.3.1生成静态库

7.3.2生成动态库

1、C文件接口

1.1什么是当前路径?

进程开始启动时,进程所在的路径默认就是当前路径

1.2程序默认打开的文件流:

  • stdin 标准输入,键盘设备
  • stdout 标准输出,显示器设备
  • stderr 标准错误,显示器设备

仔细观察发现,这三个流的类型都是FILE*, fopen返回值类型,文件指针,那什么是FILE类型呢?这是C标准库自己封装的一个结构体。

2、系统文件I/O

操作文件,除了C接口(当然,C++也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问

为什么访问文件不仅仅有C语言上的文件接口,OS必须提供对应的访问文件的系统调用?

原因:

其实上述讲的C语言接口是OS系统调用函数的封装,系统调用函数封装了C语言接口,是为了可移植性和跨屏平台性

2.1.接口介绍:

2.1.1open:

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

参数讲解;

pathname: 要打开或创建的目标文件

flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。

  • O_RDONLY: 只读打开
  • O_WRONLY: 只写打开
  • O_RDWR : 读,写打开

上面这三个常量,必须指定一个且只能指定一个

  • O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
  • O_APPEND: 追加写,不会将文件内容刷新,是进行内容的追加。

mode选项:

指明新文件的访问权限。

返回值:
成功:新打开的文件描述符
失败:-1

flags如何实现一个参数就可以有多个参数传参的效果?

我们通过flag标记位,看看哪个位上有1就输出哪一位,我们用位运算的方式来实现传多个参数的目的!

int fd1 = open("log1.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);

所以我们的flags就实现一个参数就可以有多个参数传参的效果!

注意点:

不要往文件里面书写'/0',这样会造成乱码。我们要清楚'/0'本身并不是字符串内容的一部分,而是指明字符串结束的标志。

open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限,否则,使用两个参数的open。

open函数的返回值:

open函数的返回值文件描述符到底是什么呢?

在认识返回值之前,先来认识一下两个概念: 系统调用 和 库函数

  • 上面的 fopen fclose fread fwrite 都是C标准库当中的函数,我们称之为库函数(libc)。
  • 而, open close read write lseek 都属于系统提供的接口,称之为系统调用接口
  • 回忆一下我们讲操作系统概念时,画的一张图

系统调用接口和库函数的关系,一目了然。
所以,可以认为,f#系列的函数,都是对系统调用的封装,方便二次开发

C语言的文件接口,本质就是封装了系统调用!

3.文件描述符fd

通过对open函数的学习,我们知道了文件描述符就是一个小整数

3.1 0 & 1 & 2

Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.
0,1,2对应的物理设备一般是:键盘,显示器,显示器

文件描述符的本质就是数组下标

当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。

3.2进程怎么知道了打开哪些文件呢?

每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数
组,每个元素都是一个指向打开文件的指针!
所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件!

3.3文件描述符的分配规则&&利用规则实现重定向

fd的分配规则:

最小的没有被使用的数组下标,会分配给最新打开的文件

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
close(1);
int fd = open("myfile", O_WRONLY|O_CREAT, 00644);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
fflush(stdout);
close(fd);
exit(0);
}

此时,我们发现,本来应该输出到显示器上的内容,输出到了文件 myfile 当中,其中,fd=1。这种现象叫做输出重定向。常见的重定向有:>, >>, <

使用 dup2 系统调用

#include <unistd.h>
int dup2(int oldfd, int newfd);

将旧的内容指向的指针指向了新,因此最后都只剩下old。

以后重定向只需要使用dup2函数即可。

直接完成重定向:

下图就是完成了输出重定向——>dup2(oldfd,1)

照常还是从0里面读数据,但是我们不从键盘上读了,我们从log.txt里面进行读取

4.缓冲区问题

4.1c语言为什么要存在语言层面上的缓冲区?

我们再调用fwrite的时候,有效减少我们调用系统中的write,我们要清楚调用系统调用是有成本的,时间和空间的成本,每次调用fwrite,我们可能把数据放在了语言层面的缓冲区,有效减少调用系统调用的次数,也是减少了系统拷贝的次数!本质就是用空间换时间,增加效率

4.2那什么时候开始刷新到系统当中的缓冲区呢?

  • 无刷新,无缓冲
  • 行刷新——显示器,xxxxx\n,遇到换行符就会刷新
  • 全缓冲,全部刷新——普通文件,缓冲区被写满,才会刷新
  • 自己调用fflush函数强制刷新
  • 进程退出的时候,要自动刷新

4.3缓冲区在哪里呢?

就在file*指向的结构体里面

每个文件都有一个缓冲区

4.4与fork函数的结合

为什么C语言层面的fwrite和fprintf写了两份,而write只写了一份?

fork之前就已经把3条消息打印出来了,如果向显示器进行打印,刷新方案就是行

write是直接将内容输入到了系统内部的缓冲区当中,而C语言调用的fwrite是将内容放在了语言层面的缓冲区。C语言层面的缓冲区是在FILE里面的。一旦利用write将内容放在了系统内部,那么就跟进程没有关系了

fwrite函数重定向到了普通文件,那么刷新策略就会变成全刷新,而write是输出到显示器上的,因此就是行刷新!

重定向之后,对test.txt刷新策略,缓冲区刷新策略立即变成了全缓冲,因为不会把缓冲区填满,所以在调用fork函数的时候,内容还在缓冲区当中。所以只有在进程结束的时候才会刷新缓冲区,缓冲区内保存的是进程的数据,——父进程的数据,对缓冲区进行写时拷贝,父进程有一份,子进程也有一份,所以最后才会输出两次

write函数因为是行刷新,在fork之前就已经刷新缓冲区了,就不存在将缓冲区的内容写时拷贝到子进程的情况

5、关于磁盘等相关硬件知识

系统中是不是所有的文件都被打开了呢?大部分文件都是没有被打开的。如果没有被打开的文在哪里保存呢?

答:在磁盘、SSD当中保存,那么OS要不要管理一下磁盘上的文件呢?一定要,那现在的问题就是如何让OS快速定位一个文件

5.1、磁盘的机械构成

5.2、磁盘的物理存储

每个磁盘是由一个一个小的同心圆也就是磁道组成的。

扇区:是磁盘IO的基本单位

如果我想访问磁盘中一个扇区:通过磁头进行定位到具体的磁道/柱面(cylinder),然后确定使用哪一个磁头(head),最后再确定哪一个扇区(sector)。这就是我们的CHS定位法!

那么任何文件,不就是多个扇区承载的数据!

5.3、磁盘的逻辑存储

我们其实可以把磁盘的存储当成线性结构来看待(磁带当中的长线条)。

因此我们对磁盘的管理,就变成了对数组的增删改查

我们可以采用分治的思想,将很大的内存分成多个小块,我们对每一个小块内存的管理模式可以逐个采用到其他小块,这样我们就能根据分治的思想管理更大的内存!

5.4文件系统

比如说我们将800个GB分成多个小块内存,分成10个GB,那么我们如何管理这10个GB内存的空间呢?

磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。

Linux磁盘文件特性:文件 = 内容 + 属性

内容和属性分开存储,文件名不属于文件属性!系统中,标识一个文件,用的不直接是文件名,而是inode

  • Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。将一个大的内存分成多个小块。
  • 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了!(最重要!)
  • 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用
  • inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
  • i节点表(inode table):存放文件属性。如 文件大小,所有者,最近修改时间等
  • 数据区(data block):存放文件内容

注意:

inode编号,在整个分区内唯一,不是在分组内唯一!

找一个文件,就是通过inode编号找,前提是你怎么知道你的文件在哪一个分组里面

super block为什么不每一份文件就存储一份?

这样效率太慢

super block为什么不具有唯一性:

增加容错率,如果只有一份,如果这一份信息被破坏,那么后面整个文件系统都被破坏掉了,存储多余的几份相当于备份!

inode存属性,data block存储内容

1、那我们的文件名在哪里呢?

任何一个普通文件的文件名,一定在一个目录当中!

目录是不是文件?是的!目录里面存储着文件编号(inode)+目录的内容(对应该目录存储的每一个文件名,inode编号的映射关系)

2、重谈文件的增删改查:

如果一个目录没有r,w,x权限,是创建不了文件的!因为对应着改目录文件的内容。对于一个文件,进行增删改查,都和该文件所处的目录有关系!

访问一个文件,可以根据路径前缀,优先区分出文件在哪一个分区下!

6.软硬连接:

6.1、操作观察现象:

软连接:本质是一个文件,有独立的inode

硬连接:本质不是一个独立的文件,因为它的inode编号和目标文件相同!

那硬连接出来的到底是什么呢?

一定没有新建文件,但是新的文件名,和目标文件inode构成了不同的映射关系。

6.2、软硬链接的原理

硬链接本质就是在指定的目录下,插入新的文件名和目标文件的映射关系,并让inode的引用计数++。还是同一个文件

软链接本质就是一个独立文件,软链接里面放的是目标文件的路径!软链接类似Windows下的快捷方式

6.3、软硬链接的应用场景:

软链接:对应文件的删除

删除文件时,本质是将映射关系删除,也就是引用计数--,只有当引用计数inode减到0的时候,才会真正删除文件,真正删除文件也只是讲文件的位图变成0,这也对应着我们平时删除文件的速度很快,跟下载文件的速度不成正比的原因

硬链接:

一个目录下有多少个子目录:硬连接数-2 计算得到

为什么是-2呢???

就算新建一个空目录,那么这个空目录的硬连接数就是2!

我们创建一个普通文件时,发现硬连接数就是1,因为此时的inode和文件名就一组映射关系,所以就是1.

但是创建一个空目录时,除了目录名本身的映射关系,还有. 这个文件。任何一个目录都会存在. 和.. 这两个文件,因此还有.这个映射关系,因此空硬链接数就是2!

如果此时在这个空目录下创建一个文件,那么这个目录的硬链接数就变成了3,因为还有新建文件的..增加的原先目录的映射关系

7、动静态库:

7.1基础认知

默认编译程序,用的是动态链接,如果要静态链接,-static

如果我们同时提高动态库和静态库,gcc默认使用的是动态库

如果我们只提供静态库,那么可执行程序只能对该库进行静态链接,但是程序不一定整体是静态链接的。

如果我们只提供动态库,默认只能动态链接,非得静态链接,会发生链接报错!

动态库的名称:libXXX.so 

静态库的名称:libYYY.a

库的真实名字去掉前缀和后缀,就是XXX,YYY

7.2为什么要有库:

1、提高开发效率。

2、隐藏源代码,因为我们打包的wenjian

7.3我们如何将目标文件进行打包形成一个库文件呢?

7.3.1生成静态库

ar -rc 库名 需要打包的文件

这里命令行是ar -rc,r的意思是替换,如果当前目录下存在相同名字的库就会替换原先的内容;c的意思是create,如果当前路径下不存在这个库,我们就自己进行一个创建

这里编译链接的时候已经将库包含了,为什么会报错呢?

因为gcc默认只识别C语言的库,我们自己创建的库不识别,因此我们就需要一个新命令:

-l库名,但此时也会报错,因为操作系统并不知道我们这个库具体在哪边,这时候就需要我们告诉编译器这个库是在当前路径当中!加上.文件

那如何不设置-L,我们该怎么办呢?

  • 直接将库进行安装(拷贝)到系统中
  • 通过软链接的方式:

我们也可以将我们的头文件安装到系统默认的头文件当中,把我们自己创建的库安装到系统默认的库,但是并不建议

静态库的本质是将代码拷贝到我们的程序当中,只要编译成功,形成可执行程序,那么后续就不需要静态库了

上面是静态库的使用,下面是我们的动态库的使用

7.3.2生成动态库

先将源文件编译成可执行文件。

gcc -c -fPIC 源文件名

shared: 表示生成共享库格式
fPIC:产生位置无关码(position independent code)
库名规则:libxxx.so

生成.o文件需要加上fPIC选项

动态库只需要加载一次,剩下的只需要在不同的进程地址空间进行映射就可以找到了

打包方法:

gcc -shared -o 动态库名 目标文件名

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

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

相关文章

SLAM面经1(百度)

百度面经 百度共三面,如果面试效果俱佳,会增加一个hr面。前二面主要是技术面,分为在线coding+代码知识+专业知识+工程能力。第三面是主管面,偏向于管理方面,和hr面相似。 一面 1)在线coding 在线coding的考试内容为下面力扣的变种。 2)专业面 (1)VINS-FUSION与ORB…

html+css+js网页设计 旅游 龙门石窟4个页面

htmlcssjs网页设计 旅游 龙门石窟4个页面 网页作品代码简单&#xff0c;可使用任意HTML辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 1&#…

SpringBoot3核心特性-核心原理

目录 传送门前言一、事件和监听器1、生命周期监听2、事件触发时机 二、自动配置原理1、入门理解1.1、自动配置流程1.2、SPI机制1.3、功能开关 2、进阶理解2.1、 SpringBootApplication2.2、 完整启动加载流程 三、自定义starter1、业务代码2、基本抽取3、使用EnableXxx机制4、完…

eclipse使用 笔记02

创建一个项目&#xff1a; 【File-->New-->Dynamic Web Project】 进入页面&#xff1a; Project name为项目命名 Target runtime&#xff1a;选择自己所对应的版本 finish创建成功&#xff1a; 创建成功后的删除操作&#xff1a; 创建前端界面&#xff1a; 【注意&a…

第十一章 【后端】商品分类管理微服务(11.1)——创建父工程

第十一章 【后端】商品分类管理微服务 11.1 创建父工程 项目名称:EasyTradeManagerSystem:Easy 表示简单易用,Trade 表示交易,Manager 表示管理,System 表示系统,强调系统在商品交易管理方面的便捷性,简称 etms。 新建工程 yumi-etms yumi-etms 作为所有模块的父工程,…

TortoiseSVN图标不显示的解决

解决办法一:修改svn软件的图标设置 1、选中一个文件夹或在桌面空白处,右击进入svn的setting 2、进入setting->Icon Overlays,Status cache选择Default或shell,然后点击应用 3、查看文件,图标可以正常显示 解决办法二:修改注册表的文件夹顺序 问题现象: 1、svn一直…

linux驱动开发-arm汇编基础

目录 写在前面 1、Cortex-A7 处理器有 9 种处理模式 2、Cortex-A 寄存器组 通用寄存器 1、汇编语法 2、Cortex-A7 常用汇编指令 2.1 处理器内部数据传输指令 2.1.1 传输数据操作类型 1、MOV指令 2、MRS指令 3、MSR指令 2.2、存储器访问指令 2.2.1 LDR指令 2.2.2 …

行车记录仪内存卡无法读取:问题解析与高效数据恢复策略

在智能出行的时代&#xff0c;行车记录仪作为车辆安全的守护者&#xff0c;其重要性不言而喻。然而&#xff0c;当行车记录仪的内存卡遭遇无法读取的困境时&#xff0c;不仅会影响行车记录仪的正常工作&#xff0c;更可能导致关键证据和美好回忆的丢失。本文将深入探讨行车记录…

基础 Web 开发

1. 构建项目&#xff1a; 2.添加依赖 <dependencies> <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupI…

Vue3 : ref 与 reactive

目录 一.ref 二.reactive 三.ref与reactive的区别 四.总结 一.ref 在 Vue 3 中&#xff0c;ref 是一个用于创建可读写且支持数据跟踪的响应式引用对象。它主要用于在组件内部创建响应式数据&#xff0c;这些数据可以是基本类型&#xff08;如 number、string、boolean&…

【卷起来】VUE3.0教程-09-整合Element-plus

最后一次课了&#xff0c;给个关注和赞呗 &#x1f332; 简介 Element Plus 是一个基于 Vue 3 的高质量 UI 组件库。它包含了丰富的组件和扩展功能&#xff0c;例如表格、表单、按钮、导航、通知等&#xff0c;让开发者能够快速构建高质量的 Web 应用。Element Plus 的设计理念…

在 Mac 上安装虚拟机怎么样,安装虚拟机与直接安装 Windows 系统有区别吗?

随着跨系统操作的不断发展&#xff0c;虚拟机技术在生产力领域扮演着越来越重要的角色。Mac作为一款主流的操作系统&#xff0c;也有着运行虚拟机的能力。接下来给大家介绍Mac装虚拟机好不好&#xff0c;Mac装虚拟机和装Windows系统一样吗的具体内容。 Mac装虚拟机好不好 Mac…

Flip动画的实现示例demo

Flip动画的实现示例demo 文章说明核心代码效果展示Flip动画工具类的封装 文章说明 文章主要为了学习flip动画的实现思路&#xff0c;并且采用此示例效果来理解该实现思路的含义 参考渡一前端袁老师的讲解视频 核心代码 采用简单的y轴变化的动画效果为示例 <!DOCTYPE html>…

Spring Boot 3项目使用Swagger3教程

Spring Boot 3项目使用Swagger3教程 Swagger&#xff1a;自动生成接口文档 添加依赖(pom.xml) <dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId><version>4.1…

基于双向RRT算法的三维空间最优路线规划matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 单向RRT算法 4.2 双向RRT算法 5.完整程序 1.程序功能描述 基于双向RRT&#xff08;Randomly Exploring Random Trees, 随机探索随机树&#xff09;算法的三维空间最优路径规划是一种解…

Linux 文件与目录操作命令详解

文章目录 前言创建文件1. touch2. vim 文件内容显示3. cat4. more5. less6. head7. tail 文件&#xff08;目录&#xff09;复制、删除和移动8. cp9. rm10. mv 压缩文件与解压缩11. gzip12. zip 和 unzip 创建目录13. mkdir 删除目录14. rmdir 改变工作目录15. cd16. pwd 显示目…

碰撞检测 | 图解线段几何与线段相交检测原理(附ROS C++可视化)

目录 0 专栏介绍1 线段与线段相交检测2 线段与圆相交检测3 线段与矩形相交检测4 算法仿真与可视化4.1 核心算法4.2 仿真实验 0 专栏介绍 &#x1f525;课设、毕设、创新竞赛必备&#xff01;&#x1f525;本专栏涉及更高阶的运动规划算法轨迹优化实战&#xff0c;包括&#xf…

吸浮毛宠物空气净化器推荐,希喂、小米、有哈宠物空气净化器测评

养猫需谨慎&#xff0c;不然就要做猫奴一辈子啦&#xff01;上次堂妹来我家住几天&#xff0c;刚开始还担心和猫处不来&#xff0c;不敢去摸它&#xff0c;走的时候已经约好下次来看它的时间&#xff0c;笑死我了。毕竟猫咪这么可爱&#xff0c;很少有人可以抵抗它的魅力。 这不…

想要一劳永逸地消除 AI 幻觉,该如何做?

作者:老余捞鱼 原创不易,转载请标明出处及原作者。 写在前面的话: 尽管 LLMs 基于存储、检索和生成(RAG)的方法在某些情况下能够提供准确的回答,但在面对名词短语碰撞时,RAG方法可能会因为语义相似性而失效。为了解决这个问题,本文提出了命名实体过滤(NEF)作…

SpringBoot启动成功,但端口启动失败

目录 一、问题展示 二、问题分析 2.1.端口与Tomcat的关系 2.2.问题分析 三、SpringBoot常见知识记录 3.1.SpringBoot项目常用jar包 3.1.1.必要性jar包 3.1.2.选择性jar包 3.2.标签的作用及取值 3.2.1.compile&#xff08;编译范围&#xff09; 3.2.2.provided…