inode 就是 linux 中索引的概念。
这里参考了阮一峰老师的博客:理解 inode
# 为什么需要 inode
linux 中,文件存储在硬盘,每个硬盘最小存储单位为扇区,每个扇区 512 字节。一般读取文件是按 块
做单位的,每个块一般有 8 个扇区(sector),也就是 4kb
文件存储在块中,那么需要记录存放在哪个块中,这个记录工作有 inode 也就是索引节点完成。
# inode 内容
stat file
: 查看文件索引
记录有:
文件的字节数
文件拥有者的 User ID
文件的 Group ID
文件的读、写、执行权限
文件的时间戳,共有三个:ctime 指 inode 上一次变动的时间,mtime 指文件内容上一次变动的时间,atime 指文件上一次打开的时间。
链接数,即有多少文件名指向这个 inode
文件数据 block 的位置
df -i
:查看磁盘索引。
df -h
:查看磁盘大小。
sudo dumpe2fs -h /dev/sda4 | grep "Inode size"
:查看每个 inode 节点大小
也就是说每个 inode 节点有 256B 大小。
可以看到我的 sda4 有 13156352 个索引,每个文件需要用一个索引。
也就是说索引大约占用了 3GB 存储空间,这和下面 sda4 的 197GB 正好,因为我分配磁盘大小的时候就是分配了 200GB。
# inode 号码
ls -i
:查看文件 inode 号码:
# 目录文件
linux 中目录也是一个文件,打开目录实际上在打开目录文件。
目录文件的结构非常简单,就是一系列目录项(dirent)的列表。每个目录项,由两部分组成:所包含文件的文件名,以及该文件名对应的 inode 号码。
目录文件的读权限(r)和写权限(w),都是针对目录文件本身。由于目录文件内只有文件名和 inode 号码,所以如果只有读权限,只能获取文件名,无法获取其他信息,因为其他信息都储存在 inode 节点中,而读取 inode 节点内的信息需要目录文件的执行权限(x)。(这里有点没法理解,为啥是执行权限?
# 硬链接和软连接
ln 源文件 目的文件
:硬链接
ln -s 源文件 目的文件
: 软连接
删除文件实际上在删除硬链接数,如果硬链接数为 0,就会被系统回收。
反过来,删除一个文件名,就会使得 inode 节点中的 "链接数" 减 1。当这个值减到 0,表明没有文件名指向这个 inode,系统就会回收这个 inode 号码,以及其所对应 block 区域。
这里顺便说一下目录文件的 "链接数"。创建目录时,默认会生成两个目录项:"." 和 ".."。前者的 inode 号码就是当前目录的 inode 号码,等同于当前目录的 "硬链接";后者的 inode 号码就是当前目录的父目录的 inode 号码,等同于父目录的 "硬链接"。所以,任何一个目录的 "硬链接" 总数,总是等于 2 加上它的子目录总数(含隐藏目录)。
可能这就是删除目录要用递归方式进行删除的原因,因为子目录还保留了父目录的硬链接。
软连接就是快捷方式。
# 平滑升级
1. 有时,文件名包含特殊字符,无法正常删除。这时,直接删除 inode 节点,就能起到删除文件的作用。
2. 移动文件或重命名文件,只是改变文件名,不影响 inode 号码。
3. 打开一个文件以后,系统就以 inode 号码来识别这个文件,不再考虑文件名。因此,通常来说,系统无法从 inode 号码得知文件名。
第 3 点使得软件更新变得简单,可以在不关闭软件的情况下进行更新,不需要重启。因为系统通过 inode 号码,识别运行中的文件,不通过文件名。更新的时候,新版文件以同样的文件名,生成一个新的 inode,不会影响到运行中的文件。等到下一次运行这个软件的时候,文件名就自动指向新版文件,旧版文件的 inode 则被回收。
也就是说 mv 实际上只是当前目录文件和目的目录文件中的信息。并没有发生真的移动。
而软件升级因为用的用 inode 不是文件名,这就使得,更新不会影响运行中的软件(因为软件还是再用旧的 inode)。