【Linux】Ext2文件系统、软硬链接
Ext2文件系统
- 一.理解硬件
- 1.磁盘、服务器、机柜、机房
- 2.磁盘的物理结构
- 3.磁盘的存储结构
- 4.磁盘的逻辑结构
- 1.理解过程
- 2.真实过程
- 5.CHS地址、LBA地址转换
- 二.引入文件系统
- 1.引入"块"概念
- 2.引入"分区"概念
- 3.引入"inode"概念
- 三.Ext2文件系统
- 1.宏观认识
- 2.Block Group
- 1.Super Block
- 2.Group Descriptor Table
- 3.Block Bitmap、Inode Bitmap
- 4.Inode Table、Data Block
- 3.inode 和 Data Block映射
- 4.inode 与文件名、目录
- 5.路径解析
- 6.路径缓存
- 7.挂载分区
- 8.文件系统总结
- 四.软硬链接
- 1.软链接
- 2.硬链接
本节重点:
- 理解磁盘物理结构。
- 掌握CHS地址和LBA地址。
- 掌握Ext系列文件系统原理。
- 理解分区,格式化,路径解析,挂载等过程和操作。
- 理解软硬连接使用和用途。
一.理解硬件
1.磁盘、服务器、机柜、机房


- 机械磁盘虽然在读写速度等方面不如固态硬盘,但凭借其大容量和低成本的优势,在很多领域仍有广泛的应用:大规模数据存储(机房)。笔记本主要使用的是固态硬盘。
- 计算机只认二进制,不同的硬件对于二进制的处理是不一样的。例如:磁盘可以看作由无数的磁铁组成,磁铁的南北极可以当做二进制01。
2.磁盘的物理结构

3.磁盘的存储结构

扇区:是磁盘存储数据的基本单位,512字节,块设备。修改磁盘中的数据本质是修改一/多的扇区,即便是1个byte的数据,也需要将整个扇区加载到内存中,修改后刷新到磁盘中(修改整个扇区),所以磁盘叫做块设备。而键盘与显示器是以字符为基本单位,叫做字符设备。

- 磁头摆动的本质:定位磁道(柱面)
- 磁盘盘片旋转的本质:定位扇区。
- 读写哪一个磁头的本质:读写哪一面。


CHS地址定位某个扇区:
- 可以先定位磁头(header)
- 确定磁头要访问哪一个柱面(磁道)(cylinder)
- 定位一个扇区(sector)
文件 = 内容 + 属性。都是数据,无非就是占据哪几个扇区的问题!能定位一个扇区了,就能定位多个扇区。

- 扇区是从磁盘读出和写入信息的最小单位,通常大小为 512 字节。
- 磁头(head)数:每个盘片一般有上下两面,分别对应1个磁头,共2个磁头。
- 磁道(track)数:磁道是从盘片外圈往内圈编号0磁道,1磁道…,靠近主轴的同心圆用于停靠磁头,不存储数据。
- 柱面(cylinder)数:磁道构成柱面,数量上等同于磁道个数。
- 扇区(sector)数:每个磁道都被切分成很多扇形区域,每道的扇区数量相同。
- 圆盘(platter)数:就是盘片的数量。
- 磁盘容量 = 磁头数 × 磁道(柱面)数 × 每道扇区数 × 每扇区字节数。
- 细节:传动臂上的磁头是共进退的。
柱面(cylinder),磁头(head),扇区(sector),显然可以定位数据了,这就是数据定位(寻址)方式之一,CHS寻址方式。

4.磁盘的逻辑结构
1.理解过程

磁带上面可以存储数据,我们可以把磁带 “拉直”,形成线性结构。

磁盘本质上虽然是硬质的,但是逻辑上我们可以把磁盘想象成为卷在一起的磁带,那么磁盘的逻辑存储结构我们也可以类似于:

这样每一个扇区,就有了一个线性地址(其实就是数组下标),这种地址叫做LBA。

2.真实过程
注意:传动臂上的磁头是共进退的。

柱面是一个逻辑上的概念,其实就是每一面上,相同半径的磁道逻辑上构成柱面。所以,磁盘物理上分了很多面,但是在我们看来,逻辑上磁盘整体是由 “柱面” 卷起来的。所以,磁盘的真实情况如下:
磁道:

柱面:

磁盘:

整个磁盘不就是多张二维的扇区数组表(三维数组)。所以寻址一个扇区时:先找到哪一个柱面(Cylinder),再确定柱面内哪一个磁道(磁头Head位置),最后确定扇区(Sector),所以就有了CHS。
我们之前学过C/C++的数组,在我们看来,其实全部都是一维数组:

所以,每一个扇区都有一个下标,我们叫做LBA(Logical Block Address)地址,其实就是线性地址。OS只用LBA地址,磁盘只用CHS地址!LBA地址转成CHS地址,CHS地址转换成为LBA地址,由磁盘自己来做!固件(硬件电路,伺服系统)
5.CHS地址、LBA地址转换

所以:在磁盘使用者看来,根本就不关心CHS地址,而是直接使用LBA地址,磁盘内部自己转换。
所以:从现在开始,磁盘就是一个以扇区为单位的一维数组,数组的下标就是每一个扇区的LBA地址。OS使用磁盘,就可以用一个数字访问磁盘扇区了。
二.引入文件系统
1.引入"块"概念
其实硬盘是典型的 “块” 设备,操作系统读取硬盘数据的时候,其实是不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个 “块” 。
硬盘的每个分区是被划分为一个个的 “块”。一个 “块” 的大小是由格式化的时候确定的,并且不可以更改,最常见的是4KB,即连续八个扇区组成一个 “块”。 “块” 是文件存取的最小单位。

注意:
- 磁盘就是一个三维数组,我们把它看待成为一个 “一维数组”,数组下标就是LBA,每个元素都是扇区。
- 每个扇区都有LBA,那么8个扇区一个块,每一个块的地址我们也能算出来。
- 知道LBA:块号 = LBA/8
- 知道块号:LAB = 块号*8 + n (n是块内第几个扇区)

2.引入"分区"概念
其实磁盘是可以被分成多个分区的,以Windows观点来看,你可能会有一块磁盘并且将它分区成C,D,E盘。那个C,D,E就是分区。分区从实质上说就是对硬盘的一种格式化。但是Linux的设备都是以文件形式存在,那是怎么分区的呢?
柱面是分区的最小单位,我们可以利用参考柱面号码的方式来进行分区,其本质就是设置每个区的起始柱面和结束柱面号码。此时我们可以将硬盘上的柱面(分区)进行平铺,将其想象成一个大的平面,如下图所示:


3.引入"inode"概念
到这我们要思考一个问题,文件数据都储存在 “块” 中,那么很显然,我们还必须找到一个地方储存文件的元信息(属性信息),比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为 “索引节点”。

每一个文件都有对应的inode,里面包含了与该文件有关的一些信息。为了能解释清楚inode,我们需要是深入了解一下文件系统。

所以一个文件的属性 inode 长什么样子呢?
struct ext2_inode
{//截取了部分属性__le16 i_mode; /* File mode */__le16 i_uid; /* Low 16 bits of Owner Uid */__le32 i_size; /* Size in bytes */__le32 i_atime; /* Access time */__le32 i_ctime; /* Creation time */__le32 i_mtime; /* Modification time */__le32 i_dtime; /* Deletion Time */__le16 i_gid; /* Low 16 bits of Group Id */__le16 i_links_count; /* Links count */__le32 i_blocks; /* Blocks count */__le32 i_flags; /* File flags *///备注: EXT2_N_BLOCKS = 15__le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
};

还有两个问题:
- 我们已经知道硬盘是典型的"块"设备,操作系统读取硬盘数据的时候,读取的基本单位是"块"。"块"又是硬盘的每个分区下的结构,难道"块"是随意的在分区上排布的吗?那要怎么找到"块"呢?
- 还有就是上面提到的存储文件属性的inode,又是如何放置的呢?文件系统就是为了组织管理这些的!
三.Ext2文件系统
1.宏观认识
所有的准备工作都已经做完,是时候认识下文件系统了。我们想要在硬盘上存储文件,必须先把硬盘格式化为某种格式的文件系统,才能存储文件。文件系统的目的就是组织和管理硬盘中的文件。在Linux系统中,最常见的是 ext2 系列的文件系统。其早期版本为 ext2,后来又发出 ext3 和 ext4。ext3 和 ext4 虽然对 ext2 进行了增强,但是其核心设计并没有发生变化,我们仍是以较老的 ext2 作为演示对象。
ext2 文件系统将整个分区划分成若干个同样大小的块组(Block Group),如下图所示。只要能管理一个分区就能管理所有分区,也就能管理所有磁盘文件,分治思想。

上图中启动块(Boot Block/Sector)的大小是确定的,为1KB,由PC标准规定,用来存储磁盘分区信息和启动信息,任何文件系统都不能修改启动块。启动块之后才是 ext2 文件系统的开始。
2.Block Group
ext2 文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。如下图所示:

1.Super Block
存放文件系统本身的结构信息,描述整个分区的文件系统信息。记录的信息主要有:bolck 和 inode 的总量,未使用的 block 和 inode 的数量,一个 block 和 inode 的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其它文件系统的相关信息。Super Block 的信息被破坏,可以说整个文件系统结构就被破坏了。
超级块表示的就是文件系统,文件系统以分区为单位,不同的分区可以是不同的文件系统。超级块在每个块组的开头都有以份拷贝(第一个块组必须有,后面的块组可以没有)。为了保证文件系统在磁盘部分扇区出现物理问题的情况下还能正常工作,就必须保证文件系统的 super block 信息在这种情况下也能正常访问。所以一个文件系统的 super block 会在多个 block group 中进行备份,这些 super block 区域的数据保持一致。
struct ext2_super_block
{//截取了某些属性__le32 s_inodes_count; /* 文件系统中 inode 的总数 */__le32 s_blocks_count; /* 文件系统中数据块的总数 */__le32 s_free_blocks_count; /* 文件系统中可用的空闲数据块数量 */__le32 s_free_inodes_count; /* 文件系统中可用的空闲 inode 数量 */__le32 s_first_data_block; /* 文件系统中第一个数据块的编号 */__le32 s_blocks_per_group; /* 每个块组中包含的数据块数量 */__le32 s_inodes_per_group; /* 每个块组中包含的 inode 数量 */
};
2.Group Descriptor Table
块组描述符表,描述块组属性信息,整个分区分成多个块组就对应有多少个块组描述符。每个块组描
述符存储⼀个块组的描述信息,如在这个块组中从哪⾥开始是inodeTable,从哪⾥开始是Data
Blocks,空闲的inode和数据块还有多少个等等。块组描述符在每个块组的开头都有⼀份拷⻉。
struct ext2_group_desc
{__le32 bg_block_bitmap; /* Blocks bitmap block */__le32 bg_inode_bitmap; /* Inodes bitmap */__le32 bg_inode_table; /* Inodes table block*/__le16 bg_free_blocks_count; /* Free blocks count */__le16 bg_free_inodes_count; /* Free inodes count */__le16 bg_used_dirs_count; /* Directories count */__le16 bg_pad;__le32 bg_reserved[3];
};
3.Block Bitmap、Inode Bitmap
分区后,每一个分区都格式化写入新的文件系统。
Block Bitmap:记录着Data Blocks中哪个数据块已经被占用,哪个数据块没有被占用。
Inode Bitmap:记录着inode是否空闲可用。
即便是修改Inode Bitmap中的一个比特位,也需要将所在的整个"块"加载到内存中进行修改,后再刷新到磁盘中。
4.Inode Table、Data Block
Inode Table:
- 存放文件属性,如文件大小,拥有者,最近修改时间等。
- 当前分组所有Inode属性的集合。
- inode编号以分区为单位整体划分,每一个分区都有自己的一套inode编号。inode编号可以跨组,但是不可跨分区。
- inode编号分配的时候,只需要确定每一个组的起始inode编号即可。
Data Block:
- 存放文件内容,也就是一个个的Block。
- 对于普通文件,文件的数据存储在数据块中。
- 对于目录,该目录下的所有文件名和目录名存储在所在目录的数据块中,除了文件名外,ls -l 命令看到的其它信息保存在该文件的inode中。
- Block号以分区为单位整体划分,每一个分区都有自己的一套Block号。Block号可以跨组,但是不可跨分区。
- Block号分配的时候,只需要确定每一个组的起始Block号即可。

操作系统任何管理文件系统?先描述,再组织!将Super Block和Group Descriptor Table以链表的形式管理起来,对文件系统的管理就是对链表的增删查改,所有的操作都是内存级的。
- 查找文件时:只需要知道文件的inode编号,根据每一个组的起始inode编号,先确定组的位置,再将该inode编号减去该组的起始inode编号,查找inode Bitmap,就能在inode Table中找到相应的inode,根据其中的映射关系,找到Block号,类似找Block。
- 删除文件时:先查找文件的inode,再将 Inode Bitmap 和 Block Bitmap 对应的比特位由1置为0。
- 恢复文件时:只需要知道文件的inode编号,并且将 Inode Bitmap 和 Block Bitmap 对应的比特位由0置为1。删除文件后想要恢复时,最好不要再次创建文件(可能会将删除文件的inode编号当做该新文件的inode),而是查看日志,找到删除文件的inode编号,交给专业的人去做。
- 修该文件时:先查找文件的inode,再将inode加载到内存和Block加载到文件内核级缓存区,修改后刷新到磁盘中。
- 新增文件时:先遍历Group Descriptor Table确定组,再遍历该组的inode Bitmap,获得局部的偏移量,最后根据该组的起始inode编号计算出当前的inode编号,返回给用户。
3.inode 和 Data Block映射
inode内部存在 __le32 i_block[EXT2_N_BLOCKS]; 其中EXT2_N_BLOCKS = 15,就是用来进行inode和block映射的。

4.inode 与文件名、目录
问题:
- 我们访问文件,都是用的文件名,没用过inode号啊?
- 目录是文件吗?如何理解?
答案:
- 目录也是文件,但是磁盘上没有目录的概念,只有文件属性+文件内容的概念。
- 目录的属性不用多说保存在inode中,内容保存的是:文件名和Inode号的映射关系,保存在Date Block中。
重新理解目录权限:
- 目录没有 r 权限时:无法查看目录中的文件内容,无法读取文件的inode和block。
- 目录没有 w 权限时:无法新建文件,无法将文件名和inode的映射关系写到目录的block中。
- 目录没有 x 权限时:无法进入该目录,无法打开该目录。
xzy@hcss-ecs-b3aa:~/code$ pwd
/home/xzy/code
xzy@hcss-ecs-b3aa:~/code$ ls -li
total 0
529852 -rw-rw-r-- 1 xzy xzy 0 Feb 13 17:38 Makefile
530295 -rw-rw-r-- 1 xzy xzy 0 Feb 13 17:38 test.c
529843 -rw-rw-r-- 1 xzy xzy 0 Feb 13 17:37 test.cpp
比如:要访问test.c,就必须打开test.c的工作目录,然后根据文件名test.c获得对应的inode,进而对文件进行访问。
5.路径解析
问题:打开当前工作目录文件,查看当前工作目录文件的内容?当前工作目录不也是文件吗?我们访问当前工作目录不也是只知道当前工作目录的文件名吗?要访问它,不也得知道当前工作目录的inode吗?
答案1:需要打开当前工作目录的上级目录,额…,上级目录不也是目录吗??不还是上面的问题吗?
答案2:所以类似"递归",需要把路径中所有的目录全部解析,出口是"/"根目录。
最终答案3:实际上任何文件,都有路径,访问目标文件,比如:/home/xzy/code/test.c。都要从根目录开始,依次打开每一个目录,根据目录名,依次访问每个目录下指定的目录,直到访问到test.c。这个从左向右的过程叫做Linux路径解析。

可是路径谁提供?
- 你访问文件,都是指令/工具访问,本质是进程访问,进程有CWD!进程提供路径,拼接后得到了完整路径。
可是最开始的路径从哪里来?
- 所以Linux为什么要有根目录,根目录下为什么要有那么多缺省目录?
- 你为什么要有家目录,你自己可以新建目录?
- 上面所有行为:本质就是在磁盘文件系统中,新建目录文件。而你新建的任何文件,都在你或者系统指定的目录下新建,这不就是天然就有路径了嘛!
- 系统+用户共同构建Linux路径结构。
6.路径缓存
问题1:Linux磁盘中,存在真正的目录吗?
答案:不存在,只有文件。只保存文件属性 + 文件内容。
问题2:访问任何文件,都要从根目录开始进行路径解析?
答案:原则上是,但是这样太慢,所以Linux会缓存历史路径结构。
问题3:Linux目录的概念,怎么产生的?
答案:打开的文件是目录的话,由OS自己在内存中进行路径维护。
Linux中,在内核中维护树状路径结构的内核结构体叫做: struct dentry
struct dentry
{//截取了部分内容atomic_t d_count;unsigned int d_flags; /* protected by d_lock */spinlock_t d_lock; /* per dentry lock */struct inode *d_inode; /* Where the name belongs to - NULL is*/struct hlist_node d_hash; /* lookup hash list */struct dentry *d_parent; /* parent directory */struct list_head d_lru; /* LRU list */struct list_head d_subdirs; /* our children */
};
注意:
- 每个文件其实都要有对应的dentry结构,包括普通文件。这样所有被打开的文件,就可以在内存中形成整个树形结构。
- 整个树形节点也同时会⾪属于LRU(Least Recently Used,最近最少使用)结构中,进行节点淘汰。
- 整个树形节点也同时会⾪属于Hash,方便快速查找。
- 更重要的是,这个树形结构,整体构成了Linux的路径缓存结构,打开访问任何文件,都在先在这棵树下根据路径进行查找,找到就返回属性inode和内容,没找到就从磁盘加载路径,添加dentry结构,缓存新路径。

7.挂载分区
我们已经能够根据inode号在指定分区找⽂件了,也已经能根据⽬录⽂件内容,找指定的inode了,在
指定的分区内,我们可以为所欲为了。可是:
问题:inode不是不能跨分区吗?Linux不是可以有多个分区吗?我怎么知道我在哪⼀个分区???
root@hcss-ecs-b3aa:~# ls /dev/vda* //查看磁盘: 其中vda是磁盘, vda1是分区
/dev/vda /dev/vda1
root@hcss-ecs-b3aa:~# dd if=/dev/zero of=./disk.iso bs=1M count=5 //制作一个大的磁盘块,就当做一个分区
root@hcss-ecs-b3aa:~# mkfs.ext4 disk.iso //格式化写入文件系统
root@hcss-ecs-b3aa:/# mkdir /mnt/myvda2 //建立空目录root@hcss-ecs-b3aa:/# df -h //查看可以使用的分区
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 40G 5.0G 33G 14% / root@hcss-ecs-b3aa:/# mount -t ext4 ./disk.iso /mnt/myvda2 //将分区挂载到指定的目录
root@hcss-ecs-b3aa:/# df -h //再次查看可以使用的分区
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 40G 5.0G 33G 14% /
/dev/loop0 4.7M 24K 4.4M 1% /mnt/myvda2root@hcss-ecs-b3aa:/# cd /mnt/myvda2 //进入该分区
root@hcss-ecs-b3aa:/mnt/myvda2# cd / //回到该分区
//所以: 在哪个路径下, 就能通过df -h查看在哪一个分区中root@hcss-ecs-b3aa:/# umount /mnt/myvda2 //卸载分区

root@hcss-ecs-b3aa:/mnt/myvda2# ls /dev/loop* -l
brw-rw---- 1 root disk 7, 0 Feb 13 16:31 /dev/loop0
brw-rw---- 1 root disk 7, 1 Feb 13 16:31 /dev/loop1
brw-rw---- 1 root disk 7, 2 Feb 13 16:32 /dev/loop2
brw-rw---- 1 root disk 7, 3 Feb 13 16:32 /dev/loop3
brw-rw---- 1 root disk 7, 4 Feb 13 16:31 /dev/loop4
brw-rw---- 1 root disk 7, 5 Feb 15 15:22 /dev/loop5
brw-rw---- 1 root disk 7, 6 Feb 13 16:31 /dev/loop6
brw-rw---- 1 root disk 7, 7 Feb 13 16:31 /dev/loop7
crw-rw---- 1 root disk 10, 237 Feb 13 16:31 /dev/loop-control
结论:分区写入文件系统,无法直接使用,需要和指定的目录关联,进行挂载(Mounted on)才能使用。所以,可以根据访问目标文件的 “路径前缀” 准确判断我在哪一个分区。
8.文件系统总结

四.软硬链接
1.软链接
xzy@hcss-ecs-b3aa:~/code$ ln -s file.txt file.softlink #建立file.txt的软链接文件file.softlink
xzy@hcss-ecs-b3aa:~/code$ ls -li
total 0
530971 lrwxrwxrwx 1 xzy xzy 8 Feb 15 16:06 file.softlink -> file.txt
530970 -rw-rw-r-- 1 xzy xzy 0 Feb 15 16:05 file.txt
软链接:本质是一个独立的文件,拥有独立的inode,block。其中inode保存该文件的属性,block保存的是目标文件的路径。在Windows下类似快捷方式,根据目标文件的路径打开目标文件。
xzy@hcss-ecs-b3aa:~/code$ mkdir -p dir1/dir2/dir3
xzy@hcss-ecs-b3aa:~/code$ mv test.exe ./dir1/dir2/dir3
xzy@hcss-ecs-b3aa:~/code$ tree .
.
├── dir1
│ └── dir2
│ └── dir3
│ └── test.exe
└── test.cxzy@hcss-ecs-b3aa:~/code$ ln -s ./dir1/dir2/dir3/test.exe test #给文件建立软链接
xzy@hcss-ecs-b3aa:~/code$ ls -l
total 8
drwxrwxr-x 3 xzy xzy 4096 Feb 15 18:59 dir1
lrwxrwxrwx 1 xzy xzy 25 Feb 15 19:01 test -> ./dir1/dir2/dir3/test.exe
-rw-rw-r-- 1 xzy xzy 72 Feb 15 18:55 test.c
xzy@hcss-ecs-b3aa:~/code$ ./test
Hello Linux!
xzy@hcss-ecs-b3aa:~/code$ ln -s /usr/include inc #给目录建立软链接
xzy@hcss-ecs-b3aa:~/code$ ls -l
total 0
lrwxrwxrwx 1 xzy xzy 12 Feb 15 19:04 inc -> /usr/include
xzy@hcss-ecs-b3aa:~/code$ cd inc #本质进入/usr/include目录中
xzy@hcss-ecs-b3aa:~/code/inc$ pwd
/home/xzy/code/inc
2.硬链接
xzy@hcss-ecs-b3aa:~/code$ ln file.txt file.hardlink #建立file.txt的硬链接文件file.hardlink
xzy@hcss-ecs-b3aa:~/code$ ls -li
total 0
530970 -rw-rw-r-- 2 xzy xzy 0 Feb 15 16:05 file.hardlink
530970 -rw-rw-r-- 2 xzy xzy 0 Feb 15 16:05 file.txt
硬链接:本质不是一个独立的文件,没有独立的inode。硬链接文件的inode与目标文件的inode相同,在当前目录中新增硬链接文件名与inode的映射关系。所以在Linux中可以让多个文件名对应于同一个inode。上面的2是inode中的引用计数 -> 硬链接数
xzy@hcss-ecs-b3aa:~/code$ tree .
.
└── empty└── dirxzy@hcss-ecs-b3aa:~/code$ ls -lia
total 12
529723 drwxrwxr-x 3 xzy xzy 4096 Feb 15 19:30 .
524310 drwxr-x--- 6 xzy xzy 4096 Feb 15 18:55 ..
530946 drwxrwxr-x 3 xzy xzy 4096 Feb 15 19:14 emptyxzy@hcss-ecs-b3aa:~/code$ cd empty/xzy@hcss-ecs-b3aa:~/code/empty$ ls -lia
total 12
530946 drwxrwxr-x 3 xzy xzy 4096 Feb 15 19:14 .
529723 drwxrwxr-x 3 xzy xzy 4096 Feb 15 19:30 ..
530972 drwxrwxr-x 2 xzy xzy 4096 Feb 15 19:14 dirxzy@hcss-ecs-b3aa:/$ ls -lid /
2 drwxr-xr-x 20 root root 4096 Feb 15 15:15 /
#根目录的硬链接数是20, 减去.和根目录自己, 计算出根目录下存在18个目录
结论:.是当前路径的硬链接 ..是上一级路径的硬链接
xzy@hcss-ecs-b3aa:~/code$ echo "This is 10TB data" > log.txt
xzy@hcss-ecs-b3aa:~/code$ ln log.txt /tmp/log.txt.backup #在/tmp目录下建立硬链接
xzy@hcss-ecs-b3aa:~/code$ rm -rf log.txt
xzy@hcss-ecs-b3aa:~/code$ cat /tmp/log.txt.backup
This is 10TB data
结论:硬链接可以用来文件备份
注意:
- 不能给目录进行硬链接(容易造成环型路径,硬链接的上级目录有两个,存在歧义),至于
.和..是内置的,不考虑。 - 可以给目录进行软链接(存在环型路径,但是软链接的文件类型为 l,遇到系统知道)
相关文章:
【Linux】Ext2文件系统、软硬链接
Ext2文件系统 一.理解硬件1.磁盘、服务器、机柜、机房2.磁盘的物理结构3.磁盘的存储结构4.磁盘的逻辑结构1.理解过程2.真实过程 5.CHS地址、LBA地址转换 二.引入文件系统1.引入"块"概念2.引入"分区"概念3.引入"inode"概念 三.Ext2文件系统1.宏观…...
ATF系统安全从入门到精通
CSDN学院课程连接:https://edu.csdn.net/course/detail/39573...
【算法专场】哈希表
目录 前言 哈希表 1. 两数之和 - 力扣(LeetCode) 算法分析 算法代码 面试题 01.02. 判定是否互为字符重排 编辑算法分析 算法代码 217. 存在重复元素 算法分析 算法代码 219. 存在重复元素 II 算法分析 算法代码 解法二 算法代码 算法…...
Beszel监控Docker安装
一、Beszel Hub安装 #Beszel Hub安装 mkdir -p ./beszel_data && \ docker run -d \--name beszel \--restartunless-stopped \-v ./beszel_data:/beszel_data \-p 8090:8090 \henrygd/beszel#创建账号 账号/密码:adminadmin.com/adminadmin.com 二、Besz…...
如何学习Elasticsearch(ES):从入门到精通的完整指南
如何学习Elasticsearch(ES):从入门到精通的完整指南 嘿,小伙伴们!如果你对大数据搜索和分析感兴趣,并且想要掌握Elasticsearch这一强大的分布式搜索引擎,那么你来对地方了!本文将为…...
【mybatis】基本操作:详解Spring通过注解和XML的方式来操作mybatis
mybatis 的常用配置 配置数据库连接 #驱动类名称 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver #数据库连接的url spring.datasource.urljdbc:mysql://127.0.0.1:3306/mybatis_test characterEncodingutf8&useSSLfalse #连接数据库的名 spring.datasourc…...
CSV格式和普通EXCEL格式文件的区别
CSV 文件(.csv) 普通的 Excel 文件(.xlsx 或 .xls) 主要体现在 文件格式、数据存储、功能支持 等方面: 文件格式 比较项CSV 文件 (.csv)Excel 文件 (.xlsx/.xls)文件类型纯文本文件二进制或 XML 格式数据分隔逗号(,)…...
使用 Vite + React 19 集成 Tailwind CSS 与 shadcn/ui 组件库完整指南
使用 Vite React 19 集成 Tailwind CSS 与 shadcn/ui 组件库完整指南 🌟 前言一、创建 React 19 项目二、集成 Tailwind CSS1️⃣ 安装依赖2️⃣ 配置 Vite 插件3️⃣ 引入 Tailwind4️⃣ 启动项目 三、配置路径别名1️⃣ 修改 TypeScript 配置2️⃣ 安装类型声明3…...
【java】基本数据类型和引用数据类型
在 Java 中,数据类型分为 基本数据类型 和 引用数据类型。它们的本质区别在于存储方式和操作方式。下面我会详细解释这两种数据类型,并用通俗易懂的语言帮助你理解。 1. 基本数据类型(Primitive Data Types) 基本数据类型是 Java…...
mybatis-lombok工具包介绍
Lombok是一个实用的]ava类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提高效率。 使用前要加入Lombok依赖...
2. grafana插件安装并接入zabbix
一、在线安装 如果不指定安装位置,则默认安装位置为/var/lib/grafana/plugins 插件安装完成之后需要重启grafana 命令在上一篇讲到过 //查看相关帮助 [rootlocalhost ~]# grafana-cli plugins --help //从列举中的插件过滤zabbix插件 [rootlocalhost ~]# grafana…...
零基础学CocosCreator·第九季-网络游戏同步策略与ESC架构
课程里的版本好像是1.9,目前使用版本为3.8.3 开始~ 目录 状态同步帧同步帧同步客户端帧同步服务端ECS框架概念ECS的解释ECS的特点EntityComponentSystemWorld ECS实现逻辑帧&渲染帧 ECS框架使用帧同步&ECS 状态同步 一般游戏的同步策略有两种:…...
为什么配置Redis时候要序列化配置呢
序列化和反序列化?: 序列化:将对象转换为二进制数据,以便存储到Redis中。 反序列化:将Redis中的二进制数据转换回对象,以便在应用程序中使用。 1. 默认序列化器的问题 如果不配置序列化器,Re…...
使用爬虫获取1688商品分类:实战案例指南
在电商领域,获取商品分类信息对于市场分析、选品决策和竞争情报收集至关重要。1688作为国内领先的B2B电商平台,提供了丰富的商品分类数据。通过爬虫技术,我们可以高效地获取这些分类信息,为商业决策提供有力支持。 一、为什么选择…...
C#打印设计器
C# 打印设计器,功能强大却操作简单,小白也能快速上手! 主要功能: 支持多种设计元素: 文字、图片、图形、二维码、条形码等,满足您多样化的设计需求。 灵活排版,精准定位: 支持拖拽…...
Codeforces Round 1004 (Div. 2)(A-E)
题目链接:Dashboard - Codeforces Round 1004 (Div. 2) - Codeforces A. Adjacent Digit Sums 思路 只有两种情况:n1之后没有进位,y-x1。n1之后进位(y-x-1)%90。 代码 void solve(){int x,y;cin>>x>>y;if(y-x1){cout<<…...
pnpm的使用
pnpm的使用 1.安装和使用2.统一包管理工具下载依赖 1.安装和使用 pnpm:performant npm ,意味“高性能的npm”。 pnpm由npm/yarn衍生而来,解决了npm/yarn内部潜在的bug,极大的优化了性能,扩展了使用场景。被誉为“最先进的包管理工具”。 pnpm安装指令: npm i -g p…...
vscode调试redis
系统:ubuntu redis:redis-6.0.3 1.在vs中安装c/c编译插件 2.用vscode打开redis-6.0.3 3.在菜单中找到run->Add Configuration… 4.会在目录中生成一个./vscode目录,里面包含launch.json,修改launch.json中的program:${workspaceFolder}…...
Windows逆向工程入门之汇编指令格式与操作数类型
公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 一、汇编指令格式基础 二、操作数类型详解 1. 立即数(Immediate) 2. 寄存器操作数(Register) 3. 内存操作数(Memory&#…...
亚远景-ASPICE 4.0与敏捷开发:如何实现高效协同
ASPICE 4.0与敏捷开发的结合是汽车软件开发领域的重要趋势。通过合理融合,可以实现高效协同,提升软件开发的质量和效率。以下是实现高效协同的关键要点: 1. 理解ASPICE 4.0与敏捷开发的互补性 ASPICE 4.0强调软件开发过程的规范性、可追溯性…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
