Linux操作系统的基础IO

目录

  • 系统文件IO
    • open函数
    • 0 & 1 & 2
    • 文件描述符的分配规则
    • 重定向
      • 输入重定向
      • 输出重定向
      • 追加重定向
      • dup2
    • FILE
  • 文件系统
    • inode
  • 软硬链接
    • 软链接
    • 硬链接
  • 动态库和静态库
    • 动静态库的命名方式
    • 静态库
      • 制作一个库
      • 使用库
    • 动态库
      • 制作一个库
      • 使用库

系统文件IO

open函数

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选项,来指明新文件的访问权限(比如:0666)
O_APPEND: 追加写
O_TRUNC:每次打开对文件时清理
返回值:
成功:新打开的文件描述符
失败:-1

mode_t理解:直接 man 手册,比什么都清楚。
open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限,否则,使用两个参数的open。

0 & 1 & 2

Linux任何一个进程,在启动的时候,默认会3个文件,分别是标准输入0, 标准输出1, 标准错误2.
0,1,2对应的物理设备一般是:键盘,显示器,显示器
在这里插入图片描述

🔍当调用write函数时,OS做了什么?
首先执行这个write函数的一定是你自己的进程在执行,不是其他人进程在执行,是你这个进程。当在数据写入时,你其实是调了write函数,然后操作系统识别到系统要用,然后OS就帮你去写入了。他在写入时首先要做的工作,找到你这个进程的PCB,因为是文件操作,所以他要找struct file_struct* file,然后拿着你传进来的文件描述符在数组中找到struct file*,所以就找到匹配的文件,将用户层所对应的数据直接从应用层通过这种索引方式拷贝到对应的缓冲区当中。
write或read函数本质,拷贝函数

文件描述符的分配规则

在这里插入图片描述
在这里插入图片描述
进程中,文件描述符的分配规则:在文件中描述符中,最小的没有被使用的数组元素,分配给新文件或打开的文件,依次从上向下分配。

重定向

重定向的原理:在上层无法感知的情况下,在OS内部更改进程对应的文件描述表中特定下标的指向。

输入重定向

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

输出重定向

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

追加重定向

在这里插入图片描述
在这里插入图片描述
标准输出与标准错误的区别。
在这里插入图片描述
在这里插入图片描述
因为:输出重定向,只改的是1标准输出描述符对应的指向,2号标准错误文件描述不受影响。

dup2

int dup2(int oldfd, int newfd);

函数功能:
将newfd文件夹描述符中的内容重定向到oldfd文件描述中。

FILE

因为IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件都是通过fd访问的。
所以C库当中的FILE结构体内部,必定封装了fd
我们用的编程语言,都是在操作系统的上层,用C语言时调printf调fprintf,那么这样的接口是你只是把数据从你自己写的代码当中交给了C标准库,C标准库它内部会帮我们维护对应的缓冲区,缓冲区维护好之后,它会按照自己的一定的刷新测略,将数据从你的FILE中的fd刷新到特定进程所对应的文件的缓冲区中,然后在刷新到磁盘中。

C库的刷新策略

  1. 无缓冲:是在进行写入操作时,直接刷新到OS(操作系统)中。
  2. 行缓冲:当我们将数据写到缓冲区时,只要碰到\n,就将\n前的数据刷新的OS中。
  3. 全缓冲:只有当缓冲区写满时,才将数据刷新到OS中。

显示器采用的是的刷新策略是:行缓存
普通文件采用的是的刷新策略是:全缓冲
🔍为什么要有缓冲区?
节省调用者的时间,系统调用也是要花费时间的。
🔍缓冲区在哪?
在你进行fopen打开文件时,你会得到一个FILE的结构体,缓冲区就在这个FILE结构体中。

在这里插入图片描述
在这里插入图片描述
🔍为什么出现这种现象?
首先write是系统调用接口,它不属于C标准库,调用直接写入到操作系统了。fprintf是C标准库函数,它写入数据是先写入到C标准库的的缓冲区中,然后在写入的操作系统中。
一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲。

  1. 当写向显示器
    写入显示器是行缓冲,fork之前, write fprintf已经刷新完了。

  2. 当重定向到文件中
    printf fwrite 库函数会自带缓冲区,当发生重定向到普通文件时,数据的缓冲方式变成了全缓冲。而我们放在缓冲区中的数据,就不会被立即刷新,甚至fork之后但是进程退出之后,会统一刷新,写入文件当中。但是fork的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的一份数据,随即产生两份数据。
    write函数直接写入到操作系统中。

文件系统

文件根据有没被打开可分为,打开的文件存在于内存又称为内存文件,没打开的文件存在于磁盘又称为磁盘文件,下面我们来谈谈磁盘文件。
文件 = 内容 + 属性;
Linux操作系统的文件是将内容和属性分离的。

inode

文件储存在硬盘上,硬盘的最小存储单位叫做”扇区”(Sector)。每个扇区储存512字节(相当于0.5KB)。
操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个”块”(block)。这种由多个扇区组成的”块”,是文件存取的最小单位。”块”的大小,最常见的是4KB,即连续八个 sector组成一个 block。
文件数据都储存在”块”中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为”索引节点”。
在这里插入图片描述

Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。
Boot Block :启动块,大小为1kb,由pc标准规定的,用来存储磁盘分区信息和启动信息,任何文件系统都不能操作该块.
Block Group :ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成.
超级块(Super Biock): 文件系统的所有属性信息包括文件系统的类型,文件系统整个分组的情况,Super Biock在各个分组里面可能都会存在,而且是统一更新的,是为了防止Super Biock区域坏掉。如果出现故障,整个分区不可以被使用,所以做好备份保护数据安全。它是多副本保证分区安全的策略。
Group Descriptor Table(简称GDT):组描述符,描述组属性信息,描述group内各个位置存储的信息,如Block Bitmap的起始位置和length等等

inode Table:一个文件,内部所有属性的集合用inode节点(128字节)表示,这个inode节点保存该文件所以集合属性。一个文件,一个inode。一个分组,内部也会存在大量的文件即会存在大量的inode节点。一个组区域,来专门保存该group内的所有文件的inode节点的称为 inode table也称为(inode表)。分组内部可能会存在多个inode,需要将inode区分开来, 每一个inode都会有自己的inode编号,inode编号,也属于对应文件的属性id。

Data Blocks:我们是用数据块来进行文件内容的保存的,所以一个有效文件,要保存内容,就需要[1, n]数据块,即使要保存的数据是一个字节,也要开一数据块,如果有多个文件呢?需要更多的数据块。可以将Data Blocks看做一个特别大的数组,数组的每个元素的大小是4KB数据块,所以Data Blocks就是存放所有分组文件中,用到的所有数据块。Linux查找一 个文件,是要根据inode编号,来进行文件查找的,包括读取内容! !都是根据inode编号,找到inode节点就是结构体,结构体内部会有一块地址存放Data Blocks数组的下标,这些下标所对应的数据块,就是个文件的内容。一个inode对应一 个文件,该文件inode属性和该文件对应的数据块,是有映射关系的。
inode Bitmap(inode位图):每个bit为表示node Table表中的一个inode是否空闲可用。
Block Bitmap:每个bit为表示Data Blocks数组中的下标是否空闲可用。

[whd@VM-8-16-centos 2023_10_9]$ ls -il
total 32
1572945 drwxrwxr-x 2 whd whd 4096 Oct 22 08:51 list
1314304 -rw-rw-r-- 1 whd whd   65 Oct 18 15:29 makefile
1314306 -rwxrwxr-x 1 whd whd 8496 Oct 20 09:40 myfile
1314302 -rw-rw-r-- 1 whd whd 2387 Oct 20 09:38 myfile.c
1314303 -rw-rw-r-- 1 whd whd   40 Oct 20 09:40 test.c
1314305 -rw-rw-r-- 1 whd whd  260 Oct 18 17:48 test.cc
[whd@VM-8-16-centos 2023_10_9]$ 

在这里插入图片描述
Linux系统只认inode编号,文件的inode属性中, 并不存在文件名。文件名是给用户用的。
任何一个文件,一定在一个目录内部,目录的数据块里面保存的是该目录下文件名和文件inode编号对应的映射关系,而且在目录内,文件名和inode是KV关系。
当我们访问一个文件的时候,我们是在特定目录下访问的比如(cat test.c)先要在当前目录下,找到test.c的inode编号。一个目录也是一个文件,也一定隶属于一个分区, 结合inode, 在该分区中找到分组, 在该分组中inode table中,找到文件的inode。通过inode和对应的data block的映射关系,找到改文件的数据块,并加载到OS,并完成显示到显示器。

🔍Linux如何删除文件?

  1. 根据文件名找到inode number(inode编号)。
  2. inode number找到inode属性中存放的该文件使用Data Blocks数据块的编号,根据编号将设置block bitmap对应的比特位置0即。删除内容。
  3. inode number设置inode bitmap对应的比特位设置为0。删除属性。
  4. 所以删文件只需要需改位图即可。

inode number是在一个分区内唯一有效的,不能跨分区。
🔍有没有可能,一个分组,数据块没用完,inode没了,或者inode没用完,data block用完了?
有可能,因为inode Bitmap和Block Bitmap是固定大小的。但是没办法解决。

软硬链接

软链接

ln -s myfile.txt my-soft 后者链接前者。
软连接:类似于windows的快捷键,是一个将路径很长的可执行程序,链接到当前路径下,以方便快速执行。
在这里插入图片描述
软连接是一个独立的连接文件,有自己的inode number, 必有自己的inode属性和内容。
软连接的文件内部放的是自己所指向文件的路径。所以软链接的文件大小才不一样。

硬链接

ln myfile.txt my-hard后者链接前者。
在这里插入图片描述

硬链接和目标文件公用同一个inode number,意味着硬链接一定是和目标文件使用同一个inode
硬链接没有独立的inode。
在这里插入图片描述
🔍那硬链接究竟干了什么?
建立了新的文件名与旧文件的inode的映射关系,同时将新文件与旧文件映射的同一inode结构体,inode结构体中硬链接数++,如果删除关联这个inode结构体的其中一个文件,inode结构体中硬链接数–,只有inode结构体中硬链接数为0时才是删除,这个硬链接数本质上是引用计数。
在这里插入图片描述
LInux不能给目录建立硬链接?
在这里插入图片描述
因为容易造成环路问题,比如find查找文件时。

动态库和静态库

  • 静态库(.a):是指编译链接时,把库文件的代码全部复制加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。
  • 动态库(.so):程序在运行的时候才去链接动态库的代码,一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
  • 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。

动静态库的命名方式

在这里插入图片描述
Linux动静库文件必须以lib开头 + 文件名 + .(必须是第一个.后跟,如果是动态库so,如果是静态库a)。

头文件
在这里插入图片描述
源文件在这里插入图片描述
目标文件
在这里插入图片描述
gcc编译第三方库需要携带的三个选项

  • -I:指定头文件的搜索路径
  • -L:指定库文件的搜索路径
  • -l:指定库文件的名称,只要库名即可(去掉lib,版本号以及后缀)

静态库

在这里插入图片描述

制作一个库

制作一个库必须是经过,预处理,编译,汇编的.o文件。

 ar -rc libXXXXX.a *.o

使用库

在这里插入图片描述
gcc -o mytest main.c -I ./include -L ./lib -l mymath
🔍第三方库的使用。
1.需要指定的头文件,和库文件
2.如果没有默认安装到系统gcc、g+ +默认的搜索路径下,用户必须指明对应的选项,告知编译器: a. 头文件在哪里b.库文件在哪里c.库文件具体是谁
3.将我们下载下来的库和头文件,拷贝到系统默认路径下----在Linux下安装库! ! 那么卸载呢? ?对任何软件而言,安装和卸载的本质就是拷贝到系统特定的路径下
4.如果我们安装的库是第三方的(语言(第一方库),操作系统系统接口(第二方库))库,我们要正常使用,即便是已经全部安装到了系统中,gcc/g++必须用-I指明具体库的名称

动态库

制作一个库

制作一个库必须是经过,预处理,编译,汇编的.o文件。
生成动态库

  • fPIC:产生位置无关码(position independent code)
    gcc -fPIC -c (.c文件)
  • shared: 表示生成共享库格式
    gcc -shared -o libxxxx.so (经过预处理,编译,汇编的.o文件)

在这里插入图片描述

使用库

在这里插入图片描述

gcc -o mytest main.c -I ./include -L ./lib -l mymath

这条指令,告诉gcc编译器,头文件的路径,指定库的路径,指定库的名称。

./mytest

包含动态库的可执行程序,在运行时要链接动态库。./mytest在运行时,要链接动态库。OS找不到所需的动态库在哪里,所以才运行出错。
在这里插入图片描述

🔍运行时OS是如何查找动态库呢?

  1. 更改 LD_LIBRARY_PATH(临时方案)
    LD_LIBRARY_PATH是OS链接动态库时搜索的路径,我们只需要将自己制作的动态库所在的目录追加到LD_LIBRARY_PATH 环境变量中即可。
    注意这种方法只是临时的,当你重新进入会话时这个环境变量,还需要重新添加。
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:自己制作的动态库所在的路径
    在这里插入图片描述
  2. 拷贝.so动态库文件的系统的默认搜索路径下或建立软链接。
    建立软连接将自己制作的动态库,链接到系统的默认搜索路径下/lib64
    sudo ln -s /home/whd/Code/linux/2023_10_22/otherPerson/lib/libmymath.so /lib64/libmymath.so
  3. 配置/etc/ld.so.conf.d/ldconfig更新。
    /etc/ld.so.conf.d/:目录中放的是动态链接库的配置文件。配置文件的命名可以自定义,配置文件中放动态库的绝对路径。

在这里插入图片描述

在这里插入图片描述

操作系统这三种方案其实它都是会查找处理的。

🔍为什么静态库就能找到?
链接原则:将用户使用的二进制代码直接拷贝到目标可执行程序中! 但是动态库不会!

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

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

相关文章

高等数学前置知识——二次函数

文章目录 二次函数1.1 二次函数1.2 二次函数的图像1.2.1 a > 0 时1.2.2 a < 0 时1.2.3 二次函数的平移1.2.4 普通二次型函数图像总结 1.3 其他形式的二次函数1.3.1 顶点式1.3.2 交点式 1.4 二次函数与直线的交点 二次函数 1.1 二次函数 二次函数的定义&#xff1a;y a…

C#的DataGridView数据控件(直接访问SQL vs 通过EF实体模型访问SQL)

目录 一、在DataGridView控件中显示数据 1.直接编程访问SQL &#xff08;1&#xff09;源码 &#xff08;2&#xff09;生成效果 2.通过EF实体模型访问SQL &#xff08;1&#xff09;源码 &#xff08;2&#xff09;生成效果 二、获取DataGridView控件中的当前单元格 …

1024 云上见 · 上云挑战(ChatGPT搭建)

【玩转1024】使用函数计算X通义千问搭建AI助手&#xff0c;参与1024小说创作大赛 【使用函数计算X通义千问搭建AI助手&#xff0c;参与小说创作大赛】&#xff1a;本活动基于函数计算X 通义千问快速部署 AI 个人助手应用&#xff0c;用户可以根据需要选择不同角色的AI助手开启…

刀具磨损状态识别(Python代码,MSCNN_LSTM_Attention模型,初期磨损、正常磨损和急剧磨损分类,解压缩直接运行)

1.运行效果&#xff1a;刀具磨损状态识别&#xff08;Python代码&#xff0c;MSCNN_LSTM_Attention模型&#xff0c;初期磨损、正常磨损和急剧磨损&#xff09;_哔哩哔哩_bilibili 环境库&#xff1a; NumPy 版本: 1.19.4 Pandas 版本: 0.23.4 Matplotlib 版本: 2.2.3 Keras …

【C语言】【goto语句】复习捡拾~

goto语句可以在同一个函数内跳转到设定好的位置&#xff1a; #include<stdio.h> int main() {printf("hello world\n");goto next;printf("hehe"); next:printf("leap here\n");return 0; }goto 语句如果使⽤的不当&#xff0c;就会导致在…

构建外卖小程序:技术要点和实际代码

1. 前端开发 前端开发涉及用户界面设计和用户交互。HTML、CSS 和 JavaScript 是构建外卖小程序界面的主要技术。 <!-- HTML 结构示例 --> <header><h1>外卖小程序</h1><!-- 其他导航元素 --> </header> <main><!-- 菜单显示 -…

vm_flutter

附件地址 https://buuoj.cn/match/matches/195/challenges#vm_flutter 可以在buu下载到。 flutter我也不会&#xff0c;只是这个题目加密算法全部在java层&#xff0c;其实就是一个异或和相加。 反编译 package k;import java.util.Stack;/* loaded from: classes.dex */ pu…

【Linux】部署单机项目以及前后端分离项目

Linux部署单机项目&#xff1a; 优点&#xff1a; 简化了系统管理&#xff1a;由于所有服务都在同一台机器上运行&#xff0c;因此可以简化系统管理和维护。 提高了性能&#xff1a;由于没有网络延迟和其他因素的影响&#xff0c;所以可以提高系统的性能。 缺点&#xff1a; 容…

SSH安全登录远程主机

SSH服务器简介 SSH即Security SHell的意思&#xff0c;它可以将连线的封包进行加密技术&#xff0c;之后进行传输&#xff0c;因此相当的安全。 SSH是一种协议标准&#xff0c;其目的是实现安全远程登录以及其它安全网络服务。 SSH协定&#xff0c;在预设的状态下&#xff0c;…

系统架构设计师之系统应用集成

应用集成是指两个或多个应用系统根据业务逻辑的需要而进行的功能之间的相互调用和互操作。应用集成需要在数据集成的基础上完成。应用集成在底层的网络集成和数据集成的基础上实现异构应用系统之间语用层次上的互操作。它们共同构成了实现企业集成化运行最顶层会聚臭成所需要的…

开源利器:it-tools 项目介绍

作为一名开发人员&#xff0c;我们在日常工作和学习中常常需要使用一系列小工具&#xff0c;如JSON格式化、JSON转表格、当前时间戳、XML格式化、SQL格式化、密码生成以及UUID生成等。通常情况下&#xff0c;我们会在网上搜索各种在线工具来满足这些需求。然而&#xff0c;这些…

私有云:【2】AD域的安装

私有云&#xff1a;【2】AD域的安装 1、使用vmwork创建虚拟机2、启动配置虚拟机3、安装域服务4、配置域服务器 1、使用vmwork创建虚拟机 新建虚拟机 稍后安装操作系统 选择win2012&#xff0c;如下图 设置名称及路径 分配硬盘大小&#xff0c;默认60G即可 镜像选择win2012的is…

【网安AIGC专题10.19】论文6:Java漏洞自动修复+数据集 VJBench+大语言模型、APR技术+代码转换方法+LLM和DL-APR模型的挑战与机会

How Effective Are Neural Networks for Fixing Security Vulnerabilities 写在最前面摘要贡献发现 介绍背景&#xff1a;漏洞修复需求和Java漏洞修复方向动机方法贡献 数据集先前的数据集和Java漏洞Benchmark数据集扩展要求数据处理工作最终数据集 VJBenchVJBench 与 Vul4J 的…

SSM度假村管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 度假村管理系统是一套完善的信息系统&#xff0c;结合SSM框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要 采用B/S模式开发…

系列二十五、@Configuration的作用及解析原理

一、作用 Configuration是用来代替传统的xml的配置方式配置bean的。 二、不加Configuration注解不能配置bean吗 能。 三、加与不加的区别 3.1、区别 加了Configuration注解&#xff0c;会为配置类创建cglib动态代理&#xff0c;Bean方法的调用就会通过容器getBean进行获取…

七层负载均衡 HAproxy

一、HAproxy 1、负载均衡类型&#xff1a; (1) 无负载均衡&#xff1a; 没有负载均衡&#xff0c;用户直接连接到 Web 服务器。当许多用户同时访问服务器时&#xff0c;可能无法连接。 (2) 四层负载均衡&#xff1a; 用户访问负载均衡器&#xff0c;负载均衡器将用户的请求…

深入探究深度学习、神经网络与卷积神经网络以及它们在多个领域中的应用

目录 1、什么是深度学习&#xff1f; 2、深度学习的思想 3、深度学习与神经网络 4、深度学习训练过程 4.1、先使用自下上升非监督学习&#xff08;就是从底层开始&#xff0c;一层一层的往顶层训练&#xff09; 4.2、后自顶向下的监督学习&#xff08;就是通过带标签的数…

毅速丨金属3D打印能替代传统制造吗?

金属3D打印技术已经逐渐被很多行业认可和应用&#xff0c;但是目前&#xff0c;金属3D打印多数被作为传统制造技术的一种补充&#xff0c;暂时还不能完全替代传统制造。 金属3D打印使用的是金属粉末进行选择性激光烧结&#xff0c;打印时在成型缸里铺上金属粉末&#xff0c;打印…

2023-10-27 LeetCode每日一题(切割后面积最大的蛋糕)

2023-10-27每日一题 一、题目编号 1465. 切割后面积最大的蛋糕二、题目链接 点击跳转到题目位置 三、题目描述 矩形蛋糕的高度为 h 且宽度为 w&#xff0c;给你两个整数数组 horizontalCuts 和 verticalCuts&#xff0c;其中&#xff1a; horizontalCuts[i] 是从矩形蛋糕…

牛客题霸 -- HJ52 计算字符串的编辑距离

解题步骤&#xff1a; 参考代码&#xff1a; int main() {string s1;string s2;while (cin >> s1 >> s2){int ms1.size();int ns2.size();//增加空白字符&#xff0c;修正下标的映射关系s1 s1;s2 s2;//多卡一行&#xff0c;多开一列vector<vector<int&…
最新文章