Linux 文件 IO 管理(第三讲:文件系统)

Linux 文件 IO 管理(第三讲:文件系统)

  • 进程为什么默认要打开文件描述符为 0,1 和 2 的文件呢?
  • 文件系统
    • 物理磁盘
      • 简单认识
      • 存储结构
      • 对磁盘存储进行逻辑抽象
      • 分组 —— 文件系统
        • Block Bitmap
        • inode Table
        • inode Bitmap
        • GDT(Group Descriptor Table)
        • Super Block
        • 格式化
      • 文件系统细节
        • inode number
        • datablocks[N] 数组
        • 编号唾手可得?
        • 理解文件的增删查改
        • 逆向路径解析和如何找到文件自己所在分区

进程为什么默认要打开文件描述符为 0,1 和 2 的文件呢?

我们写的程序,本质上都是 对数据进行处理(计算,存储等等),既如此就肯定有三个问题:

  • 数据从哪里来
  • 数据去哪里
  • 用户要不要看到这个过程

程序变成进程之后数据并不全是硬编码而成的,也有比如 scanfcin 的数据等等,所以是为了更好地让进程获取数据,动态地让用户看到进程的结果,毕竟这些现象都是和人来往的

归结到底,还是人有这个需求罢了,是历史的原因

文件描述符2标准错误文件 为什么也要被打开呢?

其实 标准错误文件 对应的文件也是 显示器文件,咱可以来验证一下:

int main()
{fprintf(stdout, "fprintf hello stdout\n");fprintf(stderr, "fprintf hello stderr\n");return 1;
}

咱们分别往 标准输出和错误 打印数据,但结果就是两条打印结果都在显示器上

所以在刚开始,文件描述符为 12 的两个下标其实指向同一个文件罢了;如果你 重定向,那也只是重定向 文件描述符1 的下标,所以 标准错误 仍然会往显示器打印,如下:

[exercise@localhost redirection]$ ./Test > log.txt
fprintf hello stderr
[exercise@localhost redirection]$ cat log.txt
fprintf hello stdout
[exercise@localhost redirection]$ 

那为什么还要有 2 呢?
程序运行输出的消息无非就是 正确错误 两类

而正常 Debug 的时候,会将 正确 的调试信息往 1 里打印,错误 的调试信息往 2 里打印,未来我们只需要做一次 重定向 就可以 将正确和错误的调试信息分开

./Test 1>ok.log 2>err.log

正确调试信息 都在 ok.log 文件里,错误调试信息 都在 err.log 文件里

要是想把两种信息写在别的文件里,可以这样:

./Test 1>all.log 2>&1

如此就都在 all.log 文件里了

文件系统

之前谈到的都是被打开的文件,但是磁盘上的大量文件里,被打开的只是少量文件,还有大量没有被打开的啊!

没有被打开的文件是在 磁盘 内存放,所以这种文件也被叫做 磁盘文件

可是你要打开某个文件都是要先找到这个文件,也就是在大容量磁盘里寻找此文件,所以必须要有 文件路径 + 文件名 才能在偌大的磁盘空间里找到此文件

没有被打开的文件 无非就是要放在磁盘中存放,还是那句话,存放的意义就是有朝一日可以更好的取走,所以在本质上就是在 研究文件如何存取的问题

物理磁盘

简单认识

计算机只认识二进制是公认的,而 0 ,1 是被规定出来的,其表示形式可能大不相同,可能使用高低电平表示,也有可能使用磁极表示,所以在物理上会有不同的表现

磁盘拆开就发现里面会有圆形反光的结构,叫做 盘片盘片可读可写可擦除 ,一片盘片两面都可以存数据

接续拆,会发现不止一个盘片,而是一摞盘片,是由很多盘片组合而成的结构,盘片越多,容量越大

而每一个盘面都会有一个磁头(一面一个磁头),磁头通常是用于在特定的盘面当中来回寻址

磁盘的本质是一个机械设备 ,一般磁盘在加电工作的时候,盘片会在类似马达的带动下高速旋转,而磁头会进行左右摆动,由于速度极快,所以磁头和盘片不能紧挨着,不然会造成两个硬件不可逆的损伤,所以 磁头其实是悬浮在盘面上的

存储结构

怎么存就怎么取,这是很正常的想法,所以必须要了解磁盘的内部结构

我们知道磁盘内部有一摞 盘片,每一个 盘片 的正反两面都可以写数据,而每一面都会配备一个 磁头,所以,要想精准找到想要的数据,就要确定数据存放在哪个 磁头

每一个 盘面 又被划分为一圈圈同心圆,这一圈圈就是 磁道,如果从一摞盘片的角度看,相同半径的磁道会构成 柱面,而一旦找到了数据在哪个 磁头 下,就可以确定数据在那一圈 磁道(柱面)

盘面 上一圈圈 磁道 并非磁盘的 最小读写单位,因为人们又将盘面均等的过圆心分开,那么一圈圈磁道就被分为好多 扇区,这 扇区 才是磁盘最小的 读写单位,也就是说不论读取修改与否,都是要将一整个 扇区 的内容送进内存

那么现在要想确定数据的位置,只需要知道 磁头(Header),柱面(Cylinder),扇区(Sector) 的编号即可(CHS定址法

对磁盘存储进行逻辑抽象

其实无论是内存还是外存,我们对其抽象均为 线性结构 ,磁盘内盘面虽然是一圈圈磁道,但拉直依然是直线结构,所以 磁盘整体的抽象结果就是线性的

想象你现在把一圈圈磁道拉直了,变成了直线,那现在唯一可以度量这条直线的就只剩下扇区了,而每一个扇区(sector)的大小均固定,那是不是就可以抽象成为 数组 啊,基本单位就是 扇区 sector disk_array[N] ,而数组会有自己的 下标,那么 在无形之中就相当于为每一个扇区完成编址

那怎么 将这个数组里的扇区下标转换为CHS 地址 呢?其实每一个盘片里的空间都是一样大的,扇区大小数量也一样,非常均等,所以可以通过计算找出 CHS 参数:

假设一块磁盘里,每一个盘面共有 N 个扇区,M 个磁道,那么每个磁道里就有 N / M 个扇区,而 index 是任意扇区在 sector disk_array[N] 里的索引下标

首先要明白,上面的数组是抽象出来的,而真正磁盘的每一个盘面都是从 0 开始标号的,并不是接着上一个盘面编号,不然还抽象什么呀

// num 表示一个磁道有几个扇区
num = N / M;
// 计算位于哪一个盘面,即磁头编号
Header = index / N;
// 计算出所在盘面后,使用 temp 存储 index 编号处于该盘面的下标
temp = index % 1000;
// 利用 temp 直接计算出磁道编号
Cylinder = temp / num;
// 同样 temp 取模得到扇区编号
Sector = temp % num;

这时 index 地址完美映射成为 CHS 地址

上面的工作其实是 磁盘内部直接完成的(比较简单),所以 OS 使用的一直都是抽象出来的虚拟磁盘地址

所以目前为止,文件 = 数组内很多个 sector 的下标内容构成 ,只需要记录下该文件所占的扇区下标,将其送往磁盘,再经过映射,即可完美定位磁盘文件位置

上面的问题是解决了,可是磁盘的一个扇区大小为 512 字节(现在可能是 4KB),OS 觉得太小;如果系统只是需要小小的 4KB 的数据,那 IO 端口就得完成来回 8 次拷贝,效率问题凸显!!!

一般而言,虽然磁盘被访问的 基本单位是 0.5 KB OS 未来和磁盘交互的时候,基本单位是 4 KB(后续博文会说明为什么是 4KB),也就是一次性要拿 8 个 sector ,如此提高 IO 效率问题

那么 OS 就不以 0.5 KB 进行访问,而是 4 KB,这 4 KB 是连续的 8 个扇区 sector ,被称之为

既然 OS 不愿意以扇区为基本单位进行抽象,那就 用块来抽象,那么此时 8 个扇区组成一个基本单位为块,使用下标为连续的块进行编址,那么目前为止 文件 = 数组内很多个 块 的下标内容构成

那现在还怎么使用下标来定位磁盘位置啊?很简单啊,现在的一个块是 8 个扇区,那么 下标值乘以 8 就是这个块开头扇区的原来编号,至此于 OS 而言,未来读取数据可以以块为单位

很显然,块的大小既然是固定的,那么现在只需要知道磁盘的总容量,就可以确定抽象后的每一块磁盘地址,有多少块,每个块的块号,如何转移到对应的多个 CHS 地址之类的全都知道

而块的编号叫做 LBA (Logical Block Address)逻辑块地址 ,也就是 LBA block[N] ,以一个数字来描述磁盘空间的地址,以数组的形式组织起来,妥妥的 先描述,再组织,此后 对磁盘的管理就转变为对数组的管理

如果磁盘空间太大不好管理,那么分区就浮出水面,只要把其中的小分区管理好,其他分区使用一样的方法就能实现管理了啊,分区如何实现呢?只需要记住所有分区的开始和结束的 LBA ,如此分区完成

那么现在 文件就是由很多个 LBA 块组成

分组 —— 文件系统

很显然,分完区还是很大,都是以 100GB 为单位的,所以还需要进行分组,分完组一个组的大小 可能 为 10GB ,相同的问题,只要管理好这 10GB 的小组就能管理好分区,进而就能管理好整个磁盘

而上面的一整套思想被称为 分治思想

我们之前就就说 文件 = 内容 + 属性 ,所以文件在磁盘存储,本质上是存储文件的内容数据 + 文件的属性数据,而 Linux 文件系统特定:文件内容和属性分开存储 ,要想理解这些,就得先理解分组后的一个小组,被称为 磁盘级文件系统 的东西:

在这里插入图片描述

一个 Block group 就是一个分组,也就是 磁盘文件系统Linux ext2文件系统):

  • Block Groupext2 文件系统会根据分区的大小将其划分为数个 Block Group ;每个 Block Group 都有着相同的结构组成
  • 超级块(Super Block):存放文件系统本身的结构信息Super Block 的信息被破坏,可以说整个文件系统结构就被破坏了;记录的信息主要有:
    • blockinode 的总量
    • 未使用的 blockinode 的数量
    • 一个 blockinode 的大小
    • 最近一次挂载的时间
    • 最近一次写入数据的时间
    • 最近一次检验磁盘的时间
    • 等其他文件系统的相关信息
  • GDTGroup Descriptor Table):块组描述符,描述块组属性信息
  • 块位图(Block Bitmap):Block Bitmap 中记录着 Data Block 中哪个数据块已经被占用,哪个数据块没有被占用
  • inode 位图(inode Bitmap):每个 bit 表示一个 inode 是否空闲可用
  • i 节点表:存放文件属性 ,如:文件大小,所有者,最近修改时间等
  • 数据区 Data Block :存放文件内容,是整个分组系统里占据空间最大的区域(九成以上) ,里面都是基本单位大小为 4 KB 的数据块,只存储文件的内容 ,每个块都有其块号

注意 文件加载到内存就是以块为单位分批加载,没有即使文件的最后一个块没有占完,而这一整个块也都是此文件的,只是内容不是此文件的内容而已

Block Bitmap

这是 块位图理想情况下Data Block 里有多少个块 Block Bitmap 就会申请多少个比特位,也就是说 Data Block 里的每一个数据块都对应 Block Bitmap 里的一个 bit 位,如此在 Data Block 里,数据块的占用状态就能被表示出来

注意 bit 位的位置也和数据块一一对应,不能有差错,未来想要为新文件分配空间,可以直接扫描 Block Bitmap 位图,查出 bit 位为 0 的数据块分配即可

inode Table

这玩意就是所谓的 i 节点表,这里面宏观上,其实也全都是数据块,但里面保存的是 所有文件的所有属性

Linux 中文件的属性是大小固定的集合体,就是将所有可以准确描述文件的属性集合在一起成为一个结构体,那也就是说一个文件的内容可以不一样大,但 它们的属性结构体一定是一样大的,这是每个文件都要有的,只是不同的文件属性值不同罢了 ,此乃 先描述

那么在内核里就一定存在 struct inode 结构体,可以描述任意一个文件,里面包含文件的所有属性 ,在里面存在一个非常重要的字段 int inode_number;inode 编号,因为在 struct inode 结构体内部是没有文件名属性的,但是在内核层面,每一个文件都要有 inode number ,我们通过 inode 号去标识一个文件

在 Linux 里可以通过 ls -li 指令查看磁盘文件的 inode number

现在我也知道了一个文件的 inode 号,但是我要怎么找到文件内容的位置呢?在结构体里还会存在属性 int datablocks[N] 用于标识该文件占据的所有块号

在 Linux 系统里, struct inode 结构体 大小一般固定为 128 Byte,而现在一个块的大小为 4KB ,那么一个块就能存储 32 个 inode,每一个文件都有一个 inode

那我怎么知道 inode 的使用情况呢?

inode Bitmap

当然啦,和 Block Bitmap 相同的作用:

比特位的位置 表示第几个 inodeinode number);比特位的内容,表示该 inode 是否被占用

有几个 inodeinode Bitmap 里就有几个比特位

GDT(Group Descriptor Table)

块组描述符,顾名思义:描述块组信息

该结构体主要描述当前分组的基本情况(相当具体),如:块大小,共有多少个 inode ,共有多少个 Data Blocks ,有多少个块没有被使用,有多少个 inode 被使用了等等,都会被记录在此结构体中

说白了就是个管理字段,用来管理整个块组的使用情况

Super Block

超级块 :存放文件系统本身的结构信息,这是存放一个分区的基本信息,上面的简介里也提到存放的相关内容

既然是一整个分区的基本内容,那为啥放在 0 号分组里?不应该单独于所有分组进行存放吗?

并不是每一个分组都有 Super Block,一般会根据实际的文件系统,可能存在于 2 ~ 3 个分组里,但是即便有好几个分组里都有,但大家的 Super Block 内容都是一样的

为什么要这么干呢?纯纯浪费空间啊?都是一样的内容有什么好存的呢?

既然是存放一整个分区的使用情况,说明极为重要啊!磁盘是个机械设备,靠磁头和盘片的物理旋转来定位物理空间,而 Super Block 也并不大,可能就是其中的几个扇区,如果因为一些特殊原因把 Super Block 内容刮花,导致数据失真,那后果就是这个分区都会挂掉,这个影响是巨大的!!!

所以虽然没必让整个分区的所有组都有 Super Block ,但咱还是需要选中几个幸运分组来多保存几份 Super Block ,这是出于安全考量,让文件系统更具有健壮性

格式化

现在我们知道了,一块磁盘仅仅分区是不够的,还需要分组;分完组也是不够,还需要在分组后的所有分组里写入上述 Block Group 结构内容来管理数据

那么日后我们在用磁盘的时候,是基于这么一套文件系统之上来新建删除修改等等

而在每一个分区内进行分组,然后写入文件系统的管理数据,这个叫做 格式化!!!

所以啊,格式化的本质: 在磁盘中写入文件系统

文件系统细节

inode number

寻找任何文件只能通过 inode 编号,所以这个必须知道

inode 编号是以分区为单位整体分配的,而不是分组;一个分区内部的任意文件的 inode 编号都不能重复,但两个分区可能会出现重复,所以 inode 不能跨分区访问!!!

inode 被分配的时候,是按照区域进行划分的:在 Super Block 里会记录当前整个分区的 inode 编号范围;在 GDT 里会记录当前整个分组的 inode 编号范围

当拿到一个文件的 inode 编号后,就可以对照分区和分组的范围,确定文件所属的分组位置,找到所属分组后,对照 inode bitmap 合法与否,合法可直接定位 i 节点表找到该文件

当然 Data Block 里的块号也是如此!是基于分区为单位来整体分配的!而且当文件被分配到某个组后,会优先分配该组 Data Block 里的块, 除非此文件非常大,要不然不会跨组存储

datablocks[N] 数组

其实里面就是指向该文件所使用的数据块

这是将文件属性和文件内容存储位置相关联的属性,而这 N 一般为 15

如果是 15 ,那只能映射到 15 个 data block 数据块,那一个文件最大 15 * 4KB = 60 KB 吗?肯定说不通

其实这 15 个空间里面,前 12 个是 直接映射 的,也就是可以直接指向文件存储的数据块编号;后 2 个则是 间接映射 的,可以通过这 2 个来寻找 2 个数据块单元,但这数据块单元里全都是此文件的存储地址,从而完成扩容;而最后一个存的就厉害了,它指向一个数据块单元,但是这个数据块单元里又指向其他的数据块单元,其他的数据块单元才指向真正的文件存储单元

这就很大了,可以直接映射也可以间接映射(3级甚至是4级)

那如果文件容量大于分组空间?当然是可以的,因为只要文件愿意,依然可以让 datablocks[N] 数组指向其他的分组,所以是 支持跨组访问 的!但 非常不建议这么做,因为文件较大,可能不是存在相邻的组中导致同一个文件零碎存储,跨度大,磁盘寻址时间较长,导致效率过低

在这里插入图片描述

编号唾手可得?

我们使用文件可是使用的文件名,但 OS 找文件却是用的 inode number ,很反直觉啊!而且 inode 文件属性里还不包括文件名!怎么回事?

首先用户在电脑里所处位置一定是目录,那目录是文件吗?肯定是!那就有它自己的属性和内容,所以目录也会有自己的 inode ,和普通文件有着相同的属性字段,只是属性的值不一样罢了

属性可以理解,那目录的内容呢?放什么?目录的内容其实放的是:目录名和 inode number 的关系映射

所以每次打开查看一个目录的内容时,都是通过文件名和其编号的映射关系,才找到文件的 inode number

/ 目录是 系统规定 的,是一定可以找到的,所以每次找文件,都是会对文件路径进行逆向路径解析,但这操作是 OS 自己做的,只是 Linux 会为用户缓存常用的路径,不至于每次都要逆向到 / 目录

所以现在就可以解释:

  • 在同一个目录下为什么不能创建同名文件
  • 目录的 r 权限(查看),本质上是是否允许我们 读取 目录的内容(文件名和 inode 号的映射关系)
  • 目录的 w 权限(新建删除),本质上是是否允许我们向目录进行 修改写入 (文件名和 inode 号的映射关系)
理解文件的增删查改

新建文件:在特定的分区中申请一个 inodeSuper Block 也会记录下最近的 inode 编号的分配,确定好分组的编号后再进入此分组中查找 inode bitmap ,寻找为 0 的 bit 位,计算出 inode 编号,并在 inode table 的对应位置填写属性;再去查找 Block Bitmap 寻找空间分配给该文件,并将数据块的地址和属性进行映射;最后将文件内容进行保存,并将 inode 编号返回和文件名进行映射完成新建

查找 就不谈了,有文件名和 inode 编号就很简单; 修改 也是,只是分为修改属性或内容罢了

删除文件:需要在 inode Bitmap 里找到要删的文件的位置,由 1 置为 0 ;再找到 inode 属性里的 datablocks[N] 数组,将对应在 Block Bitmap 的数据块地址由 1 置为 0 ,此时就完成了

所以啊如果一个文件被误删了,只要还没有被覆盖,是可以恢复出来的!

逆向路径解析和如何找到文件自己所在分区

在云服务器上,一般都只有一个盘,查看:

ls /dev/vda

v 代表虚拟,而 /dev/vda1 则是虚拟出来的一个分区,在 Linux 上要访问一个分区是要将一个分区进行挂载的

挂载 意思是说:将磁盘分区和文件系统的一个目录进行关联,未来我们进入一个分区其实是进入指定的一个目录

指令 df -h

在这里插入图片描述

上图红框就是将 /dev/vda1/ 目录挂载

挂载有什么作用呢?就相当于将此分区和目录进行绑定,然后进入该目录,就是在该分区进行文件操作

而不管怎么样,任何文件在被访问之前,一定有目录,只要有目录,对比目录的字符串前缀来确定自己究竟在哪个分区

所以,目录本身除了可以定位文件,还能确定分区

那么找到一个文件就简单了,现在进程提供一个文件的路径,那么路径的末尾就是文件名,需要根据文件名寻找它自己的 inode number ,如何找?需要再上一级目录的文件内容里寻找嘛,那如何获取上一级目录的文件内容?路径里由上级目录名对吧?然后获取它的 inode 编号才能读取需要的文件 inode 编号对吧?那这个目录的 inode 编号又怎么获取?

显然是不是要一直 逆向解析路径,然后一路回退至 / ,此时再返回回来找文件名和 inode 编号的映射即可

其实每一个文件的寻找过程都是这样的,只是会将常用路径进行缓存,所以会效率会比较高

怎么缓存路径?是不是要用数据结构来描述,再将其以树状结构组织起来?没错,这个数据结构在 Linux 里叫做 struct dentry用于缓存路径

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言实现归并排序(Merge Sort)

目录 一、递归实现归并排序 1. 归并排序的基本步骤 2.动图演示 3.基本思路 4.代码 二、非递归实现 1.部分代码 2.代码分析 修正后代码: 归并过程打印 性能分析 复杂度分析 归并排序是一种高效的排序算法,采用分治法(Divide and Con…

【芋道源码】gitee很火的开源项目pig——后台管理快速开发框架使用笔记(微服务版之本地开发环境篇)

后台管理快速开发框架使用笔记(微服务版之本地开发环境篇) 后台管理快速开发框架使用笔记(微服务版之本地开发环境篇) 后台管理快速开发框架使用笔记(微服务版之本地开发环境篇)前言一、如何获取项目&#…

计算机毕业设计宠物领养网站我的发布领养领养用户信息/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序

目录 1.课题背景 2.课题意义 ‌ 3.技术介绍 4.技术性需求 4.1后端服务‌: 4.2 前端展示‌ 5.数据库设计‌: 6.系统性能‌: 7.安全性‌: 8. 功能介绍: 9. 部分代码 1.课题背景 近年来,随着宠物饲养数量…

2024年9月25日--- Spring-IOC 1

一 Spring的概要 1.1 简介 Spring,春天的意思,意指给软件行业带来春天。2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发…

《深度学习》—— ResNet 残差神经网络

文章目录 一、什么是ResNet?二、残差结构(Residual Structure)三、Batch Normalization(BN----批归一化) 一、什么是ResNet? ResNet 网络是在 2015年 由微软实验室中的何凯明等几位大神提出,斩获…

linux信号 | 学习信号三步走 | 全解析信号的产生方式

前言:本节内容是信号, 主要讲解的是信号的产生。信号的产生是我们学习信号的第二个阶段。 我们已经学习过第一个阶段——信号的概念与预备知识(没有学过的友友可以查看我的前一篇文章)。 以及我们还没有学习信号的第三个阶段——信…

89个H5小游戏源码

下载地址:https://download.csdn.net/download/w2sft/89791650 亲测可用,代码完整,都是htmljs,保存到本地即可。 游戏截图:

Universal Link配置不再困扰,Xinstall来帮忙

在移动互联网时代,App的推广和运营至关重要。而Universal Link作为一种能够实现网页与App间无缝跳转的技术,对于提升用户体验、引流至App具有显著效果。今天,我们就来科普一下Universal Link的配置方法,并介绍如何通过Xinstall这款…

TypeScript 设计模式之【备忘录模式】

文章目录 备忘录模式:时光机器的魔法备忘录模式的奥秘备忘录模式有什么利与弊?如何使用备忘录模式来优化你的系统代码实现案例备忘录模式的主要优点备忘录模式的主要缺点备忘录模式的适用场景总结 备忘录模式:时光机器的魔法 想象一下,如果…

25 基于51单片机的温度电流电压检测系统(压力、电压、温度、电流、LCD1602)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机,通过DS18B20检测温度,滑动变阻器连接数模转换器模拟电流、电压,通过LCD1602显示,程序里设置温度阈值为40,电流阈值为60&am…

万博智云CEO王嘉在华为全联接大会:以创新云应用场景,把握增长机遇

一、大会背景 2024年9月19-21日,第九届华为全联接大会将在上海世博展览馆和上海世博中心举办。作为华为的旗舰盛会,本次大会以“共赢行业智能化”为主题邀请了众多思想领袖、商业精英、技术专家、合作伙伴、开发者等业界同仁,从战略、产业、…

Nginx基础详解3(nginx.conf核心代码讲解、常用命令解析、Nginx日志切割)

续Nginx基础详解2(首页解析过程、进程模型、处理Web请求机制、nginx.conf语法结构)-CSDN博客 目录 8.nginx.conf核心代码 8.1错误日志 8.1.1第一列: 8.1.2第二列: 8.1.3第三列: 8.2 #pid 8.3http模块&#xff…

A开头的词根词缀:-ate+a-+ab\abs+ab\c\d\f\g\n\p\r\s\t+ad+amph+an+ana+ante+anti+anthrop+

ate -ate,它是英语单词中的后缀词缀。它加在词根或词干上分三种词性。 首先第一种词性adj.(形容词),它主要加缀在名词词根或词干上构成的形容词:……的,有……的,像……的,For example:accurate(adj.正确的&#xff…

如何实现全行业证照一站式结构化识别?Textln企业资质证照识别上线!

企业经营活动中,资质证书是证明企业具备某项行业准入的必要证件。但企业资质证书种类繁多,各行各业的资质证书都有差异,同一行业、不同地区出具的资质证书版式也各不相同,通过传统标注训练的方式难以全量覆盖各类企业资质证照的识…

【JAVA开源】基于Vue和SpringBoot的墙绘产品展示交易平台

本文项目编号 T 049 ,文末自助获取源码 \color{red}{T049,文末自助获取源码} T049,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

机器人顶刊IEEE T-RO发布无人机动态环境高效表征成果:基于粒子的动态环境连续占有地图

摘要:本研究有效提高了动态环境中障碍物建模的精度和效率。NOKOV度量动作捕捉系统助力评估动态占用地图在速度估计方面的性能。 近日,上海交通大学、荷兰代尔夫特理工研究团队在机器人顶刊IEEE T-RO上发表题为Continuous Occupancy Mapping in Dynamic …

【C语言】手把手带你拿捏指针(完)(指针笔试、面试题解析)

文章目录 一、sizeof和strlen的对⽐1.sizeof2.strlen3.sizeof与strlen对比 二、数组和指针笔试解析1.一维数组2.字符、字符串数组和字符指针代码1代码2代码3代码4代码5代码6 3.二维数组4.总结 三、指针运算笔试题解析代码1代码2代码3代码4代码5代码6 一、sizeof和strlen的对⽐ …

线性跟踪微分器TD详细测试(Simulink 算法框图+CODESYS ST+博途SCL完整源代码)

1、ADRC线性跟踪微分器 ADRC线性跟踪微分器(ST+SCL语言)_adrc算法在博途编程中scl语言-CSDN博客文章浏览阅读784次。本文介绍了ADRC线性跟踪微分器的算法和源代码,包括在SMART PLC和H5U平台上的实现。文章提供了ST和SCL语言的详细代码,并讨论了跟踪微分器在自动控制中的作用…

排序--希尔排序

希尔排序介绍 希尔排序核心思想就是:1,分组;2,直接插入排序:越有序越快 希尔排序就是多次利用直接插入排序的一个排序算法. 希尔排序的算法思想:间隔式分组,利用直接插入排序让组内有序,然后缩小分组再次排序,直到组数为1希尔排序的理论基础就是直接插入排序越有序越快; 希尔排…

Redis-----通用命令(keys, exists, del, expire, ttl, type)

通用命令 一. 前言.1.1 通用命令1.2 Redis常用的数据类型1.2.1 String(字符串)1.2.2 List(列表)1.2.3 Set(集合)1.2.4 Hash(哈希)1.2.5 Zset(有序集合) 二. 通…