Linux - 进一步理解 文件系统 - inode - 机械硬盘

详谈机械磁盘

在上一篇博客当中,已经对 用户级缓冲区 和 系统缓冲区 的区别,和 初步认识 C 库函数 封装的 文件接口这些做了阐述。具体可以参考下述博客:

Linux - 用户级缓冲区和系统缓冲区 - 初步理解Linux当中文件系统-CSDN博客

本博客将在上篇博客的基础之上,对 Linux 当中的 文件系统进行进一步理解。


 当前 很多 用户级笔记本电脑,使用的都是 SSD 的 固态硬盘,而在可能 10 年之前,很多计算机使用还是 磁盘这种硬件设备来 存储 数据。我们所熟知的 机械硬盘 和 磁盘是同一个概念,机械硬盘是一种使用磁盘作为数据存储介质的计算机硬件设备。

像上述就是一个 机械硬盘,当在访问数据之时,主轴上的马达会带动 盘片,顺时针或者是逆时针高速旋转,磁头臂 带动 顶部的 磁头 在盘片的半径上 来回移动。

当 机械硬盘停止 工作,断电时,磁头臂就会回到 磁头停靠点。而盘片是双面的,磁头访问数据也是 双面进行访问的。

同样,上述是一个盘片,如果想要增大 容量可以叠加 盘片 和 磁头,磁头臂。 

需要注意的是:

  • 磁头臂 和 盘片的盘面是不接触的,尽管我们看上去很近,但实际上是不接触的。 
  • 而且,在机械硬盘启动之时,一般是不能随便移动的,因为这毕竟的是机械结构来运行的,何况,在上述看来,机械硬盘是一个很精密的 设备。很小的震动都可能会在很短的时间之内 让 磁头 和 磁头臂 与 盘面进行接触,从而刮花 盘面。而盘面上存储的是数据,就可能会损坏数据的存储的  二进制信息。
  • 所以,笔记本电脑,手机等等移动设备就不适合 机械磁盘,但是像服务器数据存储,这些设备十几年多不动的,就非常适合 便宜的 机械硬盘。
  • 而且,在拆开,查看机械硬盘之时,需要非常的小心,要带上手套等等的防护措施,因为 磁头 和 盘面之间的间隙很小,如果在盘面上落上一点大一点的灰尘,都可能导致盘面被刮花。
  • 磁盘当中对数据进行写入和读取,其实是磁头在对应位置进行充放电,来进行写入的读取。机械硬盘在外部接受到表示二进制数据的电信号,把这个电信号 利用磁头 在对应位置进行充放电,那么在盘面上的对应位置就表示一个 二进制的数据。 
  • 机械硬盘当中访问数据和写入数据,其实本质上和 吸铁石的原理差不多;我们可以用另一块吸铁石 来检测 另一块吸铁石当中的 某一端 是 N级 还是 S级,同样,就可以使用 N级 和 S级来表示 二进制数据。 
  • 在机械硬盘当中,可以使用 充放电来 改变 某一个 位置 的两端 N级 和 S级,从而达到修改数据的 效果。
  • 如果想销毁磁盘当中的数据,我们知道 高温是能够退磁的,但是要想把磁盘当中的所有数据销毁干净,成本还是有点高的。
  • 如果我们单纯的在软件层面,对数据进行删除,例如 rm -f xxx 这种操作的话,其实是有风险的。因为,修改操作,就是退磁或者加磁的操作,难免就会有磁性的残留,这些就是残留的二进制数据,那么,如果残留量不少,是可以进行二次修复的。这种数据称之为 -- 影子数据

 在盘面上,有很多个同心圆,这些同心圆是有宽度的,如上述黄色标注示例。就和操场跑道类似,只不过在 盘面上是圆形的线,这些线 是有宽度的,而且是同心的。

 把这些有宽度的 同心圆线,切分成一小段一小段的 区域,我们把这些区域称之为扇区,如上述在同心圆线当中,画出“一格一格”的小区域,就是扇区,如果放大来看就是这样的:

像上述的一圈一圈的黑线,就是一个一个的同心圆(磁道),而上述的红色扇形区域就是 -- 扇区

磁盘上被访问的 基本单元是一个一个的 扇区。--- 一般是 512 Byte。我们可以把磁盘看做是 由 无数个 扇区所构成。 

所以,我们要想把数据存入到磁盘当中,第一个要解决的问题就是要定位一个 扇区

要定位任意一个扇区,先要判断这个扇区在哪一面,而判断在哪一面其实就是判断 在哪一个磁头。然后在判断在哪一个 磁道,在判断在磁道的哪一个扇区当中。

所以,磁头在上下摆动本质上 就是在寻找 对应 磁道 和 扇区的过程


所以 ,其实在 机械硬盘 看来,通电之后所做的 机械运动越多,效率也就越低;反之,做的 机械运动越少,效率也就越高;因为 从固态硬盘的 光电信号的修改和访问速度看来,所以有的 机械运动就太慢了。

所以,对于软件的制造者,也就是在磁盘上存储数据的算法,一定是要尽可能的把 相关数据放在一起

 这样才能是一次访问 我们 想访问的多个数据,不同一次一次的在 磁盘当中去寻找。


磁盘在物理上他是圆形的,比如上述所说的 磁道,扇区等等都是类圆形的。但是,我们知道,磁带是可以其中的 存储数据的 磁条 拉扯成一个 线性 的 条状结构。

 磁带是 有两个轴承,在往一个方向进行 传送 磁条 的时候,其实,是在最上面有一个 线性的,我们可以看做是一个 类似于 "传送带" 的方式,在上述访问磁带当中的数据。

而这个 “传送带”  其实就是一个线性的 结构,我们把 磁条 单独从  磁带 当中抽出,把他线性的摆放。

其实,磁盘当中的一个一个磁道 也可以看做是一个 线性的结构。这个是我们在逻辑上理解的结构通,虽然,磁盘的盘面还是一圈一圈的 同心圆,但是,我们在访问和查找修改数据的时候,说可以 把它理解为一个 线性排列的地址结构。

可以把 机械硬盘当中的 每一个 盘面理解为一个 线性地址 存储的空间,然后,每一个盘面就是一个 线性地址 存储的空间。一个 机械磁盘存储的 地址空间 就可以这样作为 数据 增删查改的 逻辑结构。

在上述的 一个一个 盘面空间当中,又可以分为 无数个 磁道所代表的空间:

 所以,磁头在定位某一块物理地址空间的时候,其实在逻辑的一直看来,就是如下所示:

我们把每一个 盘面都上上述一样 把 逻辑结构抽象出来,那么 ,就可以得到一个 以 扇区为基本单位的 扇区数组

 这个扇区数组的每一个元素就是一个一个的扇区,所以,数组当中的一个一个下标,就代表着:机械硬盘当中,抽象出来的 一个一个扇区的地址空间。


 那么,像上述一样把 物理空间 划分为 逻辑结构之后,如何通过逻辑地址找到物理地址呢?

其实,在一个盘面的不同磁道当中,磁道距离圆心越近,那么所对应的 扇区面积就越少,也就是存储的 空间就越小。

而,每一个磁道上的扇区个数都上相等的,因为都是按照 从圆心开始的 两条线来分隔出的 一个一个 扇区,如下所示:
 

 

使用上述的方式就计算出了,28888 这个在整个机械硬盘当中的扇区编号,是在哪一个 机械硬盘当中的那一个位置了。 

  

这也是上述计算出的 物理地址。

 

 像上述,我们把 逻辑扇区地址称之为 --- LBA 地址

机械硬盘当中的地址称之为-- CHS地址

 所以,操作系统直接可以通过 LBA地址,即逻辑地址来直接 映射到 物理地址,从而访问到 机械硬盘当中的 物理地址处的空间存储的数据。

 


固体硬盘是随着 闪存技术的发展,所带来的 硬件层面的革新。

固态硬盘 的 存储效率 相对于 磁盘要高,

  1. 无机械结构:固态硬盘没有旋转盘片和移动的磁头等机械结构,数据存取更加稳定和快速。相比之下,磁盘需要等待盘片旋转到正确位置并移动磁头才能进行数据读写,这会导致访问延迟较高。

  2. 闪存技术。

  3. 随机访问速度:固态硬盘可以直接访问任意地址的数据,而磁盘需要等待盘片旋转到正确位置才能进行读写操作。

  4. 磁盘的机械部件会产生噪音,并且需要更多的电力来驱动。

在上述看来,固态硬盘 很明显要高于 磁盘。

但是相对的,固态硬盘价格也更贵。所以,一般如果在公司当中,比如是服务器,要存储大量的数据,所用的存储设备肯定是要非常大的 ,固态硬盘在价格上就不合适了。而且,磁盘 要做到 大容量 其实在硬件实现上 要比 SSD 要简单。

所以,在服务器数据的存储方面,现在大多数使用的还是 磁盘的方式来存储的。

同样,固态硬盘 也是有使用周期的,只不过我们用户使用的笔记本电脑使用周期可能就是几年,所以 SSD 也肯定是够用的。


除了上述的 几种存储的之外,还有一种 混盘。在混盘当中既有 磁盘,也有的 SSD。当用户紧急写入数据之时,就用 SSD, 这样IO的速度比较快。当电脑的当中的大部分硬件闲置之时,也就是当前电脑没有压力的时候,就慢慢的把 SSD 当中数据写到 磁盘的当中。

当然,这种在 两个盘当中交换数据肯定是有的 损耗的,而且,混盘 处于 固态硬盘 和 磁盘之间,效率比不上 固态硬盘;存储空间上 和 价格上又比不上 磁盘;而且 中间交换数据还有消耗,所以,混盘的方案 使用较少。

但是在大公司当中,为了考虑到 存储效率,可能会用上 几百台 ,上千台电脑 使用 固态硬盘的方式来对经常访问的数据进行 存储,但是,要存储 大量的数据,还是要是用 磁盘的方式,因为 固态硬盘的成本太高。

比如:用户常访问的数据就放到 固态硬盘当中,不常用的就不用放到这些的 高功耗,高效率的存储设备当中,我们一般把这种存储方式称为 -- 存储分级 或者  冷热分离

在本篇博客 Linux 当中的文件系统的描述当中,主要使用 磁盘的方式来进行 举例说明。

文件系统

我们知道,一个文件当中,有 文件的属性 和 文件的内容;所以,在磁盘当中存储的 文件数据,就包括了 要存储文件的内容 和 文件的 属性。

在磁盘当中,对于文件内容的存储,是按照 数据块 的方式来进行存储的。

在磁盘当中存储的 文件属性当中,存储的有 inode 这个属性。

而在 Linux 当中,文件磁盘当中存储,是将 属性内容 分开存储的!!!

也就是说,在硬件层面上,文件的存储的是分开存储的,分为 属性内容


磁盘的寄存器

其实,在计算机硬件组成当中,不仅仅 CPU 有自己的寄存器,其他设备(外设)也有自己的寄存器。磁盘也有自己的寄存器

比如:磁盘控制寄存器数据寄存器地址寄存器状态寄存器······

 CPU 虽然不能直接访问到 磁盘当中的数据,但是CPU有能力向外设发送一些信号

 有了上述的几个 寄存器,CPU 要想控制这个磁盘,此时是要 R(读)还是 (W)写,写那些数据,把这个数据写到 磁盘当中的那一个位置(LAB地址 来控制),在磁盘写完之前,磁盘可能是 未就绪状态吗,写完之后就是就绪状态,那么磁盘就像向这个 状态寄存器当中写入当前自己的状态,好让CPU 知道磁盘当前处于什么状态。

像上述的 数据寄存器,其实不是单纯的把数据寄存,然后写入到 磁盘,因为 寄存器当中的空间太小的,所以,一般 数据寄存器存储的是 要写入磁盘当中的数据,在内存当中的存储位置

而且,在现在的计算机当中,其实CPU已经不在管 IO 的过程了,它现在主要是在处理进程的代码的运行。

DMA芯片是主要负责 IO 工作的

 


那么,在我们的计算机当中,外存存储设备的存储空间一般是很大的,比如 500G,800G,1T 等等,都是非常大的,那么操作系统 和 CPU 要想管理这么大个空间是不好管理的。

所以,就有了分区的操作。其实,就和在分盘操作是一样的,我们在windows 当中,可能有 D 盘,C 盘,F 盘等等很多的盘,其实就是把外存存储空间 分为了很多个区。

而,在操作系统层面上,想做到分区的操作其实很简单。只需要定义一个结构体,每一个结构体对象管理一个 区的 起始地址 和 终止地址,然后用一个 该结构体类型的数据来管理这些个区就可以了:
 

struct partion
{
    int start;
    int end;
};

#define N 5 

// 数组
struct partion part[N];

我们上述并没有对 扇区数组当中存储的 地址进行修改,只是利用 结构体 和 该结构体的数组,把这个 扇区数组   划分为 空间大小不一的 不同分区。

然而在不同 分区当中访问之时,本质上还是访问的 LAB地址,然后映射到 CHS物理地址当中来访问。

所以,在进行管理整个 磁盘空间的 任务就划分为了 管理各个分区,只要把 各个分区都管理好了,就可以把 整个磁盘空间管理好。


inode 管理分区

在上去分区,我们可能分出来的是 200G,500G,那么对于这 200G,500G 同样还是大呀,还是不好管,但是相对于 单独的 1T来说,已经好了很多。

为了 管理这些个 分区,我们使用 inode。

200G 还是很大,所以,就会继续划分:

划分成 无数个 block group块。

像这种,把 大问题转化为小问题的思想,其实就是 分治

而,上述的一个一个 的 block group块 又是向如下一样划分的:
 

Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的。
 

  • bootblock:一般在磁盘的 0号位置处,也就是首元素位置放置。也有可能是在 其他分区的 0号位置处 放置(放置 磁盘的 0号位置处 存储的数据出现问题,导致操作系统软件找不到)。
  • Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子。
  • 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。
  • GDT,Group Descriptor Table:块组描述符,描述块组属性信息。
  • 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用
  • inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
  • i节点表(inode Table):存放文件属性 如 文件大小,所有者,最近修改时间等,一般大小是 128 字节。一般而言,一个文件,一个inode。所以,在一个分区当中会有很多个 inode;inode 有唯一的编号,也就相当于是这个文件的编号了。
  • Data blocks (数据区) :存放文件数据内容,以块的方式呈现,常见的是以 4kb 为大小。是文件系统的 块大小。比如:操作系统在访问 文件,或者是向文件当中写入数据,在上述情况下,就是按照 4kb 一次的方式来访问的。
     

Data blocks (数据区) 当中有 无数个个以  4kb 为大小 分割的 块。

所以,对于操作系统来存储数据的话,就是以 块 为单位来存储,那么按照 一个块是 4kb的话,就是以 一次 4kb 的方式 ,一次一次 像文件当中写数据的

这种一次加载 4 kb,可能某一次就会加载当前使用不到的数据,其实这种就是一种简单的 预加载

 一个块当中有一个 inode,在 inode 当中有一个 数组 blocks[] ,在这个数组当中就存储了 Data blocks 当中各个块 对应 块号,从而找到这些块来进行 增删查改。

在 数组 blocks[] 数组当中,前大部分的 存储的就是 当前文件的内容 所对应的块号,我们称之为 -- 直接索引

而后 小部分存储的是 用于索引出 真正存储 文件内容的块号的多级 索引,这个我们称之为 -- 多级索引

为什么是多级索引呢?因为 比如在第一个 blocks[] 的最后某一个元素,存储了 某一个 用于索引的 块号,当访问下一个块的时候,其实访问的不是这个文件真正的内容,其中其实还有索引,还可以指向 下一个块号,如果下一个块存储的就是文件内容,那么 第一个 blocks[] 的最后某一个元素 存储的就是 二级索引。

 利用这种多级索引的方式,就可以创建出很大的 文件了。


那么,在上述这么多个 块当中,我们怎么知道哪一个块有没有被使用呢?比如现在有 2.5W 这么多个 块,我怎么知道 那些块有没有被使用呢?

所以,就有用到位图!!

 如果有  2.5W 个 块,那么 块位图(Block Bitmap)当中就有 2.5W 个 比特位,用一个比特位上的 0 和 1 来表示某一个编号的上的块是否被 使用。用比特位的位置,和 块号映射。

所以,删除一个文件,不需要把这个文件对应的 块空间给删除掉。

 这就是为什么,一个非常大的文件,拷贝非常慢,但是删除非常快。

所以,像上述所说的 inode Bitmap 和 inode Table 你就可以理解了,因为  Data blocks (数据区)当中存储的文件肯定有很多个,所以 inode 也有很多个,这些都用 inode Table 来保存。 inode Bitmap 块位图(Block Bitmap) 一样都是位图,但是 inode位图(inode Bitmap) 保存的事 全部的 inode 的使用情况。

所以删除文件,只需要把inode位图(inode Bitmap)和 块位图(Block Bitmap)  当中 对应的比特位 的值做修改即可。

通过 inode bitmap 映射找到 所有的 inode 和 各个 inode 当中映射的所有的 存储 文件内容 对应的块号,然后就是对 inode位图(inode Bitmap)和 块位图(Block Bitmap)  当中 对应的比特位 的值做修改。

所以,理论上 Linux 当中是可以做到 像在 windows 当中的回收站,在回收站当中 恢复文件,在Linux当中 就是把 inode位图(inode Bitmap)和 块位图(Block Bitmap)  当中 对应的比特位 的值做 恢复。


注意:

在文件的 inode 属性当中,不包含文件的 名称!!

可以使用上述命令,在Linux 当中查看 一个文件的编号。

在Linux 当中识别某一个文件,使用的是 inode 编号。这个inode 编号就是存储在 inode 结构体当中的。 


inode 在各个当中是独立存在的。这里所说的区,其实就是  我们上述所说的 开始把 一个磁盘分区(分盘)操作。

一个分区当中,所能够使用的 inode 总数是确定的。

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

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

相关文章

【算法挨揍日记】day21——64. 最小路径和、174. 地下城游戏

64. 最小路径和 64. 最小路径和 题目描述: 给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:每次只能向下或者向右移动一步。 解题思路: 状态表示&…

量化交易:建立趋势跟踪策略的五个指标

什么是趋势跟踪策略? 趋势跟踪策略是只需需顺势而为的策略,即在价格上涨时买入,在价格开始下跌时卖出。在趋势跟踪策略中,人们的目标不是预测或预测,而只是关注市场上的任何新兴趋势。 趋势是如何出现的?…

毅速丨3D打印透气钢正在被各行业广泛应用

随着制造技术的发展,企业对生产效率和产品品质的进一步提高,3D打印透气钢已逐渐在各行业中广泛应用。传统的透气钢制造方法,如粉末冶金和扩散焊,通常只能加工出透气钢的嵌块,使用时需要进行镶嵌,存在强度不…

十八、Linux任务调度crond和at

1、crond任务调度 crond进行 定时任务的设置 概述 任务调度:是指系统在某个时间执行的特定的命令或程序。 任务调度分类:1.系统工作:有些重要的工作必须周而复始地执行。如病毒扫描等 个别用户工作:个别用户可希望执行某些程序…

Kotlin学习(一)

Kotlin学习&#xff08;一&#xff09; 1.使用IDEA构建Kotlin项目 新建工程即可 我这里选择的Build System是IntelliJ&#xff0c;虽然我没用过但是这是Kotlin基础学习应该不会用到其他依赖 2.Hello World package com.simonfun main(args:Array<String>){println(&q…

list,dict使用方法

list, dict的使用 list的使用&#xff1a; ori_list [1, 2, 3] append: 使用append为列表增加1个元素4 输出增加元素之后的列表 ori_list [1, 2, 3] ori_list.append(4) print(ori_list)extend: 给定列表[8, 7, 6],将ori_list和给定的列表进行合并 输出合并后的列表 ori_l…

统信UOS通过源码安装软件提示“configure: error: cannot run C compiled programs.”错误

1. 问题说明 使用源码的方式安装git软件&#xff0c;安装过程中出现两个错误。 编译错误“cannot run C compiled programs” XC:~/Downloads/git-2.42.1$ ./configure --prefix/home/software/git-2.42.1 configure: Setting lib to lib (the default) configure: Will try…

将word中的表格无变形的弄进excel中

在上篇文章中记录了将excel表拷贝到word中来&#xff1a; 记录将excel表无变形的弄进word里面来-CSDN博客 本篇记录&#xff1a;将word中的表格无变形的弄进excel中。 1.按F12&#xff0c;“另存为...”&#xff0c;保存类型&#xff1a;“单个文件页面”&#xff0c;保存。…

C++ Qt 学习(十):Qt 其他技巧

1. 带参数启动外部进程 QProcess 用于启动外部进程int QProcess::execute(const QString &program, const QStringList &arguments);QObject *parent; ... QString program "./path/to/Qt/examples/widgets/analogclock"; QStringList arguments; argument…

ESP32 MicroPython 蜂鸣器及传感器的使用⑦

ESP32 MicroPython 蜂鸣器及传感器的使用⑦ 1、蜂鸣器奏乐2、实验目的3、实验内容5、实验结果6、小车传感器应用7、实验目的8、实验内容9、参考代码10、实验结果 1、蜂鸣器奏乐 我们小车底板配置有蜂鸣器&#xff0c;下面我们来学习如何去利用蜂鸣器演奏乐曲 2、实验目的 学…

如何将 Docsify 项目部署到 CentOS 系统的 Nginx 中

文章目录 第一步&#xff1a;准备 CentOS 服务器第二步&#xff1a;安装 Node.js 和 Docsify第三步&#xff1a;初始化 Docsify 项目第四步&#xff1a;本地预览 Docsify 项目第五步&#xff1a;配置 Nginx 服务器第六步&#xff1a;重启 Nginx 服务器拓展&#xff1a;使用 HTT…

VisualBox7.0.12 主机和宿舍互PING设置

设置成桥接模式 主机设置 虚拟机设置

day07_数组初识

数组的概述 数组就是用于存储数据的长度固定的容器&#xff0c;保证多个数据的数据类型要一致。 数组适合做一批同种类型数据的存储 数组是属于引用数据类型&#xff0c; 数组变量名中存储的数组在内存中的地址信息。 数组中的元素可以是基本数据类型&#xff0c;也可以是引用…

[qemu逃逸] DefconQuals2018-EC3

前言 一道简单的套壳堆题.原本题目环境为 ubu16, 我这里使用的是 ubu18 设备逆向 qemu-system-x86_64 只开了 Canary 和 NX 保护. 比较简单, 主要逻辑在 mmio_write 里面, 其实现了一个菜单堆, 具有增删改的功能: 但是在释放堆块时并没有置空, 所以这里存在 UAF. 而程序还直…

.Net中Redis的基本使用

前言 Redis可以用来存储、缓存和消息传递。它具有高性能、持久化、高可用性、扩展性和灵活性等特点&#xff0c;尤其适用于处理高并发业务和大量数据量的系统&#xff0c;它支持多种数据结构&#xff0c;如字符串、哈希表、列表、集合、有序集合等。 Redis的使用 安装包Ser…

IIC通信协议

IIC是串行半双工同步总线 I2C总线为两线制&#xff0c;只有两根双向信号线&#xff0c;一根是数据线SDA&#xff0c;另一根是时钟线SCL&#xff0c;IIC总线外接两个上拉电阻作用&#xff1a;在总线处于空闲状态&#xff0c;总线处于高电平状态 IIC总线硬件连接 1、IIC总线支…

tamarin运行

首先我们找到安装tamarin的文件位置&#xff0c;找到以后进入该文件夹下 ubuntuubuntu:~$ sudo find / -name tamarin-prover /home/linuxbrew/.linuxbrew/var/homebrew/linked/tamarin-prover /home/linuxbrew/.linuxbrew/Cellar/tamarin-prover /home/linuxbrew/.linuxbrew/…

URAT串口通信协议

UART是异步串行全双工总线&#xff0c;面向设备和设备之间的连接 配置相关内容 1、串口为串行通讯方式&#xff0c;代表一个时钟周期&#xff0c;只可以收发一位数据 2、115200代表什么&#xff0c;以及115200单位 单位&#xff1a;bps(比特率、二进制/秒) 115200代表&#…

泉盛UV-K5/K6全功能中文固件

https://github.com/wu58430/uv-k5-firmware-chinese/releases 主要功能&#xff1a; 中文菜单 许多来自 OneOfEleven 的模块&#xff1a; AM 修复&#xff0c;显著提高接收质量长按按钮执行 F 操作的功能复制快速扫描菜单中的频道名称编辑频道名称 频率显示选项扫描列表分配…

mysql 实现去重

个人网站 首发于公众号小肖学数据分析 1、试题描述 数据表user_test如下&#xff0c;请你查询所有投递用户user_id并且进行去重展示&#xff0c;查询结果和返回顺序如下 查询结果和返回顺序如下所示 解题思路&#xff1a; (1) 对user_id列直接去重&#xff1a; &#xff…