文件系统理解

         先前的博客我写了关于缓冲区的理解,顺便提及了在内存的文件是怎样管理的,本文就来描述在磁盘上的文件是怎么样。但要先了解了解磁盘。

        在笔记本上机械磁盘被固态硬盘代替,因为固态硬盘更快,而且方便携带,机械硬盘若是受到外部碰撞,非常容易损坏,但在大型服务器的存储中机械磁盘几乎不会被代替,因为要控制成本,效率虽然会慢,但是这里面存的一般是用户比较旧的数据,例如一年前的聊天记录,你几乎不会再看了,所以没必要追求IO的速度,这点挺巧妙的。

        但如果是你立刻可能会看到的,例如刚发的朋友圈,那就会放在大量固态硬盘的存储集群上,既保证效率,又保证成本。

一 认识硬件---磁盘

        计算机中唯一有机械运动的设备,存储时会要有机械运动辅助,因为数据都在磁盘的一个一个的磁性区域,要寻找访问这些区域是靠机械运动,所以注定比固态硬盘这些电传输慢,因为电传输的速度貌似是接近光速的。

        摔了容易损坏,因为磁头和盘面很接近,若是在在打开状态下摔了电脑,磁头会和高速移动的盘面接触,直接损坏硬件,所以机械磁盘退出便携式笔记本是必然。同理,磁盘内也不能有灰尘,否则在高速运动下,会刮花盘面,逐渐造成数据缺失。

        学了这么久的计算机,我们很早前就听说一个常识,那就是计算机内只认识0和1,这是因为计算机内的各个硬件是靠电路链接,比较容易使电路呈现两种状态,通电,断电,假如我们想让计算机再认识一个2,那就要能让电路呈现第三种状态,只能通过电流值,例如某个电流值以下是1,以上是2,但是电流是会出现波动的,如果在传输数据时,一旦电压不稳,你本来想传2,结果变成了1,影响是什么呢,我如果让发电站故障一下,我能影响全世界的运算结果。科学家们解决不了电流稳定的问题,那就只能让电路只表示两种状态,由此计算机内一切的数据都是二进制。总而言之,所以硬盘接收到的也只能是0和1,但是磁盘不是靠电存的,但是一定要有两种状态能分别表示0,1。如下,初识磁盘的储存过程。

        首先磁盘收到来自内存的电信号,接收来自内存的数据以及存储位置,磁头拿到位置后进行定位,定位后磁盘如何存储数据,储存规则: 可以认为磁盘就是一个个小的有磁性的区域,这个磁性区域有N级和S级,规定N级在上,S级在下,这个磁性区域表示1,相反表示0,如果我们通过某种手段把这个磁性区域的磁级逆置了,就相当于往该区域写了个1或0。

        那读数据估计就是和磁头有关了,磁头判断该区域的上方是N级还是S级,从而判断这个磁性区域是1还是0。

        而要销毁这个磁铁的磁力,只能烧毁,不能直接删除文件达到删除磁盘上的数据的目的吗?不行,因为我们删除一个文件不是删数据,而是更改一些属性数据。解释文件系统和文件系统拓展时会提及,到时候我们就能理解为什么删除一个文件很快。而下载一个文件则很慢。

二 对磁盘的抽象理解

        先前已经大致了解了磁盘的大体结构,工作原理,可是磁盘上有那么多的磁性区域,我存储和读写数据如何寻址?

        设计上规定:磁盘的基本单位是一个扇区,下面是一块盘面的扇区图。一个扇区大小是512字节,一个磁道内会有多个扇区,一个完整的空心圆弧就是一个磁道,这样多个磁道就变成了一个完整盘面。

一个磁盘会有多个盘面和对应的磁头。

        所以如何寻址就变成了如何定位扇区的问题,先来看看机械运动如何确定扇区:一开始就要先确定盘面,确定让哪个磁头运动,随后磁头沿着半径运动就是在确定磁道,沿着圆弧方向就是在确定扇区。这种确定磁头,确定磁道,最后确定扇区的定位扇区方式称为CHS(英文首字母),访问磁盘的消耗:磁头确定磁道,以及盘面自转帮磁头确定扇区,所以说访问磁盘的效率取决于机械运动,读取数据的消耗似乎比找到数据的消耗还小,所以为了提高效率,一定要把数据尽量放一起,就不用进行太多的机械运动。

        噢,我知道了机械运动如何确定扇区,但是我告诉了磁盘什么数据让磁盘知道我要访问哪个扇区呢?要解释得再来看看对磁盘的抽象理解。

        我们已经知道磁盘实质上就是一个个的扇区,先把所有的扇区按顺序像数组一样整齐排列。此时我们把磁盘抽象为一个线性的大数组,那每个扇区天然就有个下标。这些下标就是扇区编号。

        我们认为各个磁道上的扇区数量是一样的,虽然外侧的圆圈更大,但为了方便理解,我们就认为外侧的扇区比较稀疏,内侧的扇区比较密集,所以扇区数量一样。而扇区编号就是书本上提到的LBA地址,所以设计者肯定是让磁盘能根据磁道号找到对应的磁道,根据扇区编号找到扇区,从而读取数据。转换如下。

        为什么还要弄一个LBA地址出来呢,你直接用个CHS地址不行吗,有一种解释是:LBA让os不用关心磁盘结构?磁盘内部有一个控制器,它负责将LBA地址转为CHS地址让磁头去访问,但对于os来说自己只使用LBA地址,就不用关心地址转换,更不用关心磁盘结构是什么,反正只要拿着这个LBA地址,磁盘会把数据给我,其它的我不关心。(老实说这里的解释我还是有点模糊,毕竟没经历太多)

        显然os不需要定义一个这么大的数组,只需要知道一个扇区多大,然后磁盘总容量多少,这样就知道了总扇区数,除以盘面,甚至可知每个盘面的扇区数,再由磁道数得知每个磁道上平均的扇区数,当然,本文是在每个磁道扇区数一致的情况下讨论的,如果不一致,那肯定要多记录一些参数。

        磁盘也有寄存器,用来快速获取cpu的指令,先告诉磁盘写还是读,再告诉磁盘读写的地址,以前是通过数据寄存器一点点传,因为最后要等寄存器数据存到了磁盘的位置,才可以继续从内存读到寄存器,现在来理解就是,计算机内还有个DMA芯片,负责IO,磁盘可以和DMA芯片合作,直接读内存数据导入到磁盘,中间不经数据寄存器,但速度快不了多少,因为时间消耗主要是写到磁盘。

三 文件系统

        磁盘划分

        我们现在只知道怎么写,但是不知道能不能写,因为不知道这个扇区有没有被占用,所以需要文件系统来管理。首先来看看磁盘空间是如何被管理的——分区管理。

        可是这实际上是一个个的扇区啊,那我怎么表示D盘有哪些扇区,很简单,用start记录起始扇区下标,end记录区域内最后一个扇区下标,然后每个分区分别初始化两个下标就可以实现分区了,而给定一个分区的容量和扇区大小,就知道这个区域内有多少扇区了,然后先前分区的end下标+1就是下一个分区的起始扇区下标,然后加上扇区数量就是下一个分区的end扇区下标。

        为什么要分区呢?首先是安全,由于分区了,每个区域都会有自己的管理系统,这样一个系统被破坏就不会影响其它区域的系统,查资料还说因为以前的病毒经常会破坏c盘,所以只能分区,让c盘承受伤害。还有个原因是好管理,下面再细说。

        如果我们的文件系统能管理200个G,那就可以把这套系统复制到其它分区,假如大小为150个G,就能管理150个G,因为200个G内文件的各种属性可以被管理,那150G的文件属性也没问题。

        分区后又分成一个个Block group(分组)。每个group block大小可能为10g。Boot Block存的是os开机后需要的管理信息,让在内存的os知道磁盘的分区情况等,有点抽象,简单理解就是存了os,可以不理会。

        为什么要再划分呢?首先文件系统肯定要加载到内存,因为文件系统本质上是os的一部分,因为磁盘也是硬件,当然要被os管理,如果你不分区分组,要加载到内存的文件系统是会占用许多内存的,分区分组后,我们进程使用了哪个文件,将文件所在分区的文件系统加载到内存即可,能省一点是一点啦。还有就是和分区原因有个公共点,那就是方便管理,如何理解方便管理呢?会在文件系统拓展解释如何文件做增删改查时顺便抛出解释。

BlockGroup内部介绍

        终于要开始讲文件系统了。

1 super block(超级块)

        首先规定着各分组中的文件系统内的GDT,Data Blocks等信息的占用的空间,分布顺序,剩余空间,还有整个分区的基本使用情况,也就是下图的内容。

        不会存在每个组上,只会存两三份,一方面是为了保险起见,多存几份,免得丢失后,os不知道磁盘的当前分区的各个分组的边界,这样就无法将inode编号转为具体扇区编号,下面介绍还有很多操作需要超级块内的信息,如果没了,那些操作都做不了了,整个分区就完蛋了,还有一方面是不能存太多份,可以理解为每次创建文件后超级块内某些信息要修改,存太多份超级块维护成本太高。

2 Group Descriptor Table(GDT)

        块组描述符。 虽然下面Block Bitmap和inode Bitmap已经描述了inode Table和Data Blocks的使用情况,但是若要统计还剩下多少个,或者说剩余有效空间大小,就得遍历Block Bitmap和inode Bitmap这比较浪费时间,所以就用Group Descriptor Table保存了,使用了一个,GDT内部的记录inode数量的变量就--,想知道数据块空间剩余,用block剩余数量*一个块大小即可。

3 InodeTable       

        一个文件的属性会被分配128字节,所以一个扇区会存在多个文件的属性,如何区分,就是用属性中的inode值。

        那inode值哪来,谁分配的,首先磁盘所有分区的inode范围是被规定好的,那由一个文件一个inode编号得出,能创建的文件是有限的,inode给各个组的分配也是规定好的,所以当要创建文件时,会先看在哪个分区创建,然后遍历分区内的小组,先在GDT看看当前组还有没有inode剩余,没有就去下个组,然后遍历inode Bitmap,有空位就用这个,然后加上当前组的起始inode(超级块存着),就是分配给文件的inode编号了。

         inode表内部存多个文件的属性,内部结构应该是类似哈希表的。如何查文件inode编号,如下图。

       这就是文件属性和内容分开存的含义,而且文件属性一定存着文件内容占了哪些块,还有文件属性内没有文件名,那我们平时找文件都是用文件名,如何和inode对应,简单理解就是目录文件的内容中会保存自己目录下的文件名和inode对应关系,没错目录也是个文件。那inode如何找到自己的内容块,在inode内有一个数组,这个数组内存的就是内容块编号。

        0下标到11下标中存块号,这些块号对应的块存文件内容,后面存的块号对应的块存的不是文件内容,而是专门存块号。12下标和13下标对应的块专门存块号,又称二级索引,大约能存2048个块号,能存内容8mb。但是不意味着文件最大只有8mb。

        14号数组内的类似三级索引,这个对应的块专门用来存二级索引的,如下图,10号块内存块号,这些块号指向的块存的还是块号,最后指向的才是内容,这样就能映射一百万个块,差不多4G了。

        

4 DataBlocks    

        存文件内容,是以块为单位的,大小是4kb,也就是说哪怕你文件只有一个字节,也要给你分配4kb,原因:虽然磁盘的基本单位是扇区,但是os在访问时却是以4kb为单位,一次刚好访问一个数据块的文件内容,就是为了减少io次数,提高效率,而且这最多只会多读一个块,但磁头运动次数大大减少了,效率还是会提高的。

        所有文件内容都在这个DataBlocks内,这该如何查找呢?

        从前面超级块的介绍得出,显然我们能从中知道一个分组的起始扇区编号,以及分组内各区域的起始扇区编号。而且一开始整个空间的大小,各个区域空间也是超级块规定好的,显然Data Blocks内的块数也是可知的,所以每个数据块天然就有了自己的编号。编号作用:知道Data Blocks的起始扇区编号和数据块大小,只要再知道数据块编号,那任意数据块的扇区编号也就知道了,就能让磁盘找到了。所以文件属性只要存了数据块编号,就能转为数据块的扇区编号,然后找到文件内容。当然还可以用来和bitmap上面的比特位进行映射,如下。

        由上得,inode和数据块数量是规定好的,所以会出现inode分配完了,但数据块还有,inode还有但是数据块没了,没办法解决。

5 Block Bitmap和inode Bitmap

        Block Bitmap和inode Bitmap分别标记inode和数据块是否被占用,比特位的位置分别和inode编号和block编号映射起来,比特位上的内容表示inode,block是否被使用,由此得我们删除文件时只要将对应这个位图上的比特位清0,然后在超级块以及GDT内修改inode和block剩余就可以了,所以删除一个文件的速度比较快。什么!你说为什么不删内容,没必要,直接让下个使用该空间的文件覆盖写就可以了,就算没覆盖完,显示文件内容时也不会影响,因为文件有大小的嘛,你别把垃圾数据算成文件大小,显示文件内容就按文件大小来显示即可。

周边问题解释1

        inode编号如何与bitmap下标对应? 首先整个分区分组的inode的数量,起始inode数值是确定的,组内的inode范围也就知道了(超级块存着),也就可以提前设置位图来管理所有的inode的。

周边问题解释2

       规定:inode值是在一个区内是唯一的,但在其它区,可能会重复,因为我们可以判断文件在哪个区,所以没必要让不同区的inode值不一样,诶你是怎么判断文件所在区的呢?简单理解就是分区的文件系统会被加载到内存中,os通过管理这个文件系统来管理整个分区,而这个文件系统会被加载到某个目录下,这个动作称为挂载,我们创建文件时也会有个路径,或许这个路径就是属于某个分区的文件系统管理,在这下面创建的都属于这个分区,所以说我们根据路径可以判断分区。

        而为了让一个分区内的文件具有唯一的标识符,所以组和组之间的inode值范围是不一样的,保证分配时不会出现一个inode标识两个文件,inode怎么判断属于哪个组呢,很简单,前面说了每个组的inode范围是知道的,所以用inode编号可以判断在哪个组,而且和block编号一样,都能被转为具体的扇区编号,此时inode值不仅在一个分区内用来标识文件,还可以用来判断所在分组,减少检索范围。

周边问题解释3

        由此得而且文件属性和文件内容应该是要在一个块组内的,因为各个分组的数据块编号是会重合的,仅仅凭借文件属性内存的数据块号是无法区分在哪个分组的。

四 文件系统拓展

        当我们大致了解了文件系统内的各个字段,接下来就开始用对这些字段的了解来解释一些问题。但还需要一点点知识准备。

1 理解目录

        我们一般访问文件都是只用文件名,例如cat test.c,找文件不是用inode吗,系统如何将文件名转为inode呢?靠目录目录也是文件,所以有自己的属性,里面有权限信息,而内容存的是目录下的文件名和inode的映射关系。        

        好,目录也是个文件,要访问文件内容就要先找到文件,找文件又要inode,那我怎么获取目录的inode,从上级目录中找,因为目录名和自己的inode就保存在上级目录文件的内容中,噢,所以找一个文件要带路径。

        诶,不对啊,到时候我们要一直找到根目录的,难道说根目录的inode操作系统知道?我觉得差不多可以这样理解,所以找到一个文件必须要有路径,例如/usr/bin/test,此时就是现在根目录下找到usr目录的inode,然后再找到bin目录的inode,然后在bin文件内容找到test文件的inode,最后找到文件属性和内容。

        那用相对路径如何查找,有相对路径的前提是先找到当前目录,然后再解析相对路径,找到分叉点,再根据路径继续找文件名和indoe的映射关系,由上得,这样太慢了,所以目录dentry缓存会记录历史上常用的目录的inode。

        目录常识底层解释

        所以说目录下不能有同名文件,因为文件名和inode是kv映射的,文件名就是key。

        创建文件要把文件名和inode写到目录的数据块中,没有"w"权限,就不能创建文件,肯定是先拿到目录文件内的权限信息了,判断后不让往数据块写。

        同理,没有"r"权限,无法ls查看目录下的文件,因为此时不让读目录文件的数据块了,也就拿不到文件的文件名和inode,更拿不到文件的属性。

        没有"x"权限,也无法cd进入该目录,去查看目录文件属性,发现目录的权限没有"x",也就不让cd了。

2 对磁盘格式化后做了什么

        按我们现在的理解就是会把文件系统上的bitmap那些字段都清空,还有就是格式化可能会用其它的文件系统来格式化,也就是说下图的文件系统字段重新写入,因为每个文件系统对分区,分组的要求可能不一样,所以一旦格式化,要改所有的文件系统信息。

3 新建文件要做什么

        先用路径判断分区(文件系统周边问题解释中曾提及),然后去GDT看组内有无剩余的inode,然后去inode Bitmap里看哪个比特位是空的,最后要加上当前组的inode起始编号,这就是分配inode的过程。还要分配数据块,也是如此,先去GDT看看有无剩余,再去数据块位图找空数据块的编号,然后把块号填入到属性中,随后就直接跳转到对应数据块写数据了。

4 那如何查找一个文件

        现在我们就知道cat test.c,是由路径找到目录文件内容(虽然我们没有明显写路径,但是环境变量提供了,你试试查看其它目录下的文件,就一定要带路径),再提供对应文件的inode值,然后用inode值确认分组,在分组内的inode Table找到文件属性,文件属性内有数据块编号,前面已经提过如何用数据块编号跳转到对应扇区。

5 删除文件要做什么

        删除一个文件,也就是删属性和内容,所以要先查找文件(参考前面查找文件)。至于删除文件的操作,先前在5 Block Bitmap和inode Bitmap介绍曾提及过,也就是改一改位图上的比特位。

6 修改一个文件做什么

        修改一个文件本质就是先查找文件属性和内容,然后再修改,所以具体操作和查找文件相同。

        由此得对文件做增删改查本质上是要对这些位图做增删查改,所以当然是位图越小越好,不然分配inode遍历位图比较费时间,所以要分区分组,把管理区域变小,才能快速遍历位图实现增删改查。

五 软硬链接

1 建立软链接

      1  ln -s d1(目录) d2(目录)

        此时会创建一个软链接,名字为d1,是和d1链接。目录d1,d2是已经创建的,目录也是文件,也可以被链接。

        会认为是要在d2下创建一个软链接和d1链接,但又没写文件名,所以会默认在d2目录下面创建一个d1文件,然后作为d1目录的软链接,但是我们写的目标文件和源文件都没带路径,这个时候出来的软链接会有问题。而且我们可以看到的是此时这个软链接名为d1,然后inode为786508,和d1的inode值786460不同,这说明软链接文件和被链接的文件是两个不同的文件。

        而如果链接对象是一个已经存在的文件,然后后面又不写路径和文件名,则会认为要在当前路径下创建一个软链接名为test.c,会引发引发命名冲突,因为软链接其实还是文件,文件名和inode要存到目录文件的内容中,所以不能重复。

        老老实实带完整路径再测试一下。此时的颜色就正常了。

        也可以正常使用。先进入d1目录查看目录下的文件,再cd d2目录下的软链接,ls查看出的文件信息是一样的。注意:我此时是用一个软链接和一个目录进行连接,才可以对软链接使用cd命令,估计是cd内部做了判断,会去获取软链接内存的路径,看看指向文件是否是目录,是目录的话,cd  test就被转换成cd /home/hay/d1。

        不带路径是默认在当前目录下创建软链接,前面不正常应该算是写了路径又没写完整。

        如果目标文件d4不存在,会创建一个目标文件d4去链接,我本来想测试目录去链接目录,现在看来没有这种情况,或许是ln命令规定创建一个链接文件作为其它目录文件,普通文件的软链接,而不是目录以及普通文件做别人的软链接,这一点我也是运气好才理解清楚。

2 软链接的本质和应用

        软链接的本质:在文件内容中存了指向文件的路径,就像是windows下的快捷方式,为什么不能存inode,因为要用路径判断分区和获取inode,再用inode判断分组找文件,所以不如直接给路径。

        软链接使用场景:可以简化使用难度,有时候我们要在当前目录下运行一个可执行文件test,但是其路径太深,每次运行都要带路径。

        我们就可以用软链接简化,直接./test就可以了,值得说明的是既然软链接内存的是被链接文件的路径,如果我们修改了这个文件的路径,此时软链接会失效。

        如果此时用硬链接呢?

        也可以跑,那我就有点疑惑了,那用硬链接和用软链接好像没区别啊?有没有种情况硬链接无法使用,只能软链接上,当然有,这就要结合软硬链接的本质来说了,硬链接如何查看文件内容呢?先通过自身的路径判断分区,然后解析路径获得inode,最终找到inode,问题就出在用自身路径判断分区上,这就规定了硬链接必须和被链接文件在同一个分区,而软链接则不需要。

3 建立硬链接

        ln 源文件 路径+硬链接名。

         对于硬链接的使用有几点要说明,1 首先被链接文件绝对不能是目录,bash会检查,不是权限的问题,而是直接的硬性要求,直接杜绝这种情况,因为容易造成环路问题。

        此时如果执行find / -name test.c,如果找到了这个硬链接,那就会跳转到root继续找,一直死循环。让find禁止对硬链接搜索治标不治本,如果很多函数都有这个问题,难道一个个禁止对硬链接操作吗,所以就直接禁止对目录进行硬链接了。

        2 如果是对test.c文件做硬链接,此时d2是个目录,不会认为是d2这个目录做test.c的硬链接,而是认为你没写目标文件名,然后在d2目录下创建一个test.c的目标文件,作为硬链接。和软链接情况类似。

4 软链接的本质和应用

         如下图,硬链接的本质是在特定目录的文件内容上增加了文件名和inode的映射关系,是在哪个目录文件的内容增加呢? 就是硬链接名前面的路径指定的目录,如果不写就是在当前目录下增加。

        软连接,硬链接的第一个区别就出来了,前者为不同文件,后者为同一文件——由被链接文件的inode的值和软硬链接文件的inode比较可得,再次证明文件属性内无文件名,如果保存了,那从文件属性内取得的文件名应该是一样的。还有个小细节,我们会发现file.txt的属性有个数值从1变成了2,这个数称为硬链接数,是什么呢?我们可以测试一下,我们发现rm删除了test.txt后,这个数-1了。

        其实就是inode内的引用计数,也就是用来记录有多少个文件名和inode数值对应,(注意:由于文件属性是struct inode,所以有时候称inode是指文件属性,而struct inode内还有个变量叫inode number,所以有时候称inode是指文件标识符inode数),那为什么inode内会有一个引用计数呢,可能就是为了服务于硬链接,免得rm文件直接就删了,而其它文件名还指向这个文件呢。

        硬链接场景:.和..就是一种硬链接,.和当前目录链接,..和上级目录链接,/的引用计数由.和子目录的..和自己构成,那为何不用软连接呢,软链接也可以和目录链接啊,我想可能是因为软链接是单独的文件,属性是和链接文件不一样的,对就是因为属性,或者说是权限属性,.和..作为硬链接的话,权限信息是不变的,而作为软链接的话,权限会发生改变,就可能使得我本来有权限访问目录,却没有权限用你这个软链接,所以就直接用硬链接。

        诶,不对啊,你前面不是说不能对目录进行硬链接吗,那.和..不就是对目录进行链接吗,不用担心,前面的环路问题是因为搜索时会对硬链接也进行搜索,os规定.和..不被搜索,就不会出问题,毕竟os是规则的制定者,有大把的方式绕开规则,我们就不行了,当然.和..的作用也很大,使得linux产生了相对路径的概念,方便我们作路径跳转。

        这篇博客中的软硬链接用到了不少文件系统的内容,为了完整性,只好放一起了,第一次写这么长的博客。

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

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

相关文章

极狐GitLab 镜像仓库使用技巧

极狐GitLab 镜像仓库 众所周知,极狐GitLab 是一个成熟、安全的一体化 DevOps 平台,其自身内置了容器镜像仓库功能,也即极狐GitLab Container Registry,用户可以将自身需要的镜像推送至极狐GitLab 镜像仓库,而无需自建镜…

JS对象笔记

对象声明 对象也只是一种数据类型/字面值。写对象这个字面值有两种写法,一种是普通的对象,这种对象用new 构造函数(),另一种是JS内特有的json对象。这个对象是直接{}就代表对象。且也是在堆内。 对象的构成 无论是上…

道路坑洞数据集(坑洞目标检测)VOC+YOLO格式650张

路面坑洞的形成原因是由于设计、施工、养护处理不当、控制不适和受气候、环境、地质、水文等自然因素影响,以及车辆的运行和车辆超载运行导致路面破损,出现坑洞的现象。 路面坑洞的分类: (1)路面混凝土板中坑洞&…

python自动化测试实战 —— CSDN的Web页面自动化测试

软件测试专栏 感兴趣可看:软件测试专栏 自动化测试学习部分源码 python自动化测试相关知识: 【如何学习Python自动化测试】—— 自动化测试环境搭建 【如何学习python自动化测试】—— 浏览器驱动的安装 以及 如何更…

SpringBoot入门知识

我是南城余!阿里云开发者平台专家博士证书获得者! 欢迎关注我的博客!一同成长! 一名从事运维开发的worker,记录分享学习。 专注于AI,运维开发,windows Linux 系统领域的分享! 本…

前端体系:前端应用

目录 前端体系基础 html(超文本标记语言) css(层叠样式单) javascript() 一、前端体系概述 二、前端框架 React Vue Angular 三、前端库和工具 lodash Redux Webpack 四、模块化和组件化 ES…

微软AutoGen框架:AI的新时代,你的新机遇

一、引言 在科技日新月异的今天,人工智能已经深入到我们生活的各个角落。无论是智能手机、智能家居还是自动驾驶汽车,人工智能的应用无处不在。而在这个领域中,微软AutoGen框架无疑是一颗璀璨的新星。它以其独特的创新性和实用性&#xff0c…

【网络通信原理之套接字】

目录 概念 分类 数据报套接字:使用传输层UDP协议 流套接字:使用传输层TCP协议 原始套接字 Socket编程注意事项 前言:本文主要介绍了在什么是套接字及在Java中套接字是什么,和在套接字编程的注意事项。 概念 Socket套接…

大数据技术之Hive(超级详细)

第1章 Hive入门 1.1 什么是Hive Hive:由Facebook开源用于解决海量结构化日志的数据统计。 Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能。 本质是:将HQL转化成MapReduce程序 …

WPF实现更加灵活绑定复杂Command(使用Microsoft XAML Behaviors 库)

1、安装NuGet 2、在XAML的命名空间引入&#xff1a; xmlns:i"http://schemas.microsoft.com/xaml/behaviors" 3、使用&#xff1a; <Canvas Background"Aqua"><Rectangle Stroke"Red" Width"{Binding RectModel.RectangleWidth}…

Java面向对象思想以及原理以及内存图解

文章目录 什么是面向对象面向对象和面向过程区别创建一个对象用什么运算符?面向对象实现伪代码面向对象三大特征类和对象的关系。 基础案例代码实现实例化创建car对象时car引用的内存图对象调用方法过程 成员变量和局部变量作用范围在内存中的位置 关于对象的引用关系简介相关…

Leetcode刷题笔记题解(C++):328. 奇偶链表

思路&#xff1a;遍历链表生成奇链表和偶链表&#xff0c;然后拼接两个链表生成新的链表。 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), ne…

JS基础之作用域链

JS基础之作用域链 作用域链作用域链函数创建函数激活总结 作用域链 当JavaScript代码执行一段可执行的代码&#xff08;execution code&#xff09;时&#xff0c;会创建对应的执行上下文&#xff08;execution context&#xff09;。 对于每个执行上下文&#xff0c;都有三个重…

恢复出厂设置后在 Android 上恢复照片的 6 种常用方法

恢复出厂设置可帮助您删除电子设备的所有信息并将其恢复到原始系统状态。但是&#xff0c;如果您不小心按下了恢复出厂设置按钮并从 Android 设备中删除了所有难忘的照片&#xff0c;该怎么办&#xff1f;好吧&#xff0c;您无需担心&#xff0c;因为可以通过以下一些方法来恢复…

Apache Flink(十三):Flink History Server

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录

区块链的可拓展性研究【05】闪电网络

1.闪电网络&#xff1a;闪电网络是一种基于比特币区块链的 Layer2 扩容方案&#xff0c;它通过建立一个双向支付通道网络&#xff0c;实现了快速、低成本的小额支付。闪电网络的交易速度非常快&#xff0c;可以达到每秒数万笔交易&#xff0c;而且交易费用非常低&#xff0c;几…

04.仿简道云公式函数实战-QLExpress基础语法

1. 前言 小伙伴大家好&#xff0c;在上一篇文章我们简单初探了QLExpress表达式引擎&#xff0c;我们简单写了一个HelloWorld的程序&#xff0c;并成功的运行期望的结果。在本篇文章中我们来熟悉一下QLExpress的语法&#xff0c;因为我们在后面简道云公式实战的时候&#xff0c…

发布 Whatsonchain 上的 BSV20 插件

我们发布了 whatsonchain 上的 BSV20 插件来验证 BSV20 代币。 对于任何交易&#xff0c;whatsonchain 都可以通过以下网址打开&#xff1a; https://whatsonchain.com/tx/{hash}我们使用此 bsv20 v21 交易 打开 Whatsonchain 。 打开whatsonchain后你会看到BSV20插件&#x…

Linux系统安装MySQL8.0版本详细教程【亲测有效】

首先官网下载安装包&#xff1a;https://downloads.mysql.com/archives/community/ 一、上传到安装服务器 二、解压 tar -xvf mysql-8.0.31-linux-glibc2.12-x86_64.tar.xz三、移动位置并重新命名 mv mysql-8.0.31-linux-glibc2.12-x86_64 /usr/local/mysql四、创建mysql用户…

官宣 | HelpLook已入驻企业微信应用市场

HelpLook正式入驻企业微信第三方应用市场。 HelpLook支持自定义域名与AI站内搜索&#xff0c;能够帮助企业微信用户搭建所见即所得的企业知识库、产品帮助中心、用户手册、企业博客。 | 怎么找到HelpLook并开始使用 在企业微信的第三方应用就可直接搜索HelpLook&#xff0c;添…