![df 如何知道使用了多少空间而不需要遍历所有文件?](https://linux22.com/image/133938/df%20%E5%A6%82%E4%BD%95%E7%9F%A5%E9%81%93%E4%BD%BF%E7%94%A8%E4%BA%86%E5%A4%9A%E5%B0%91%E7%A9%BA%E9%97%B4%E8%80%8C%E4%B8%8D%E9%9C%80%E8%A6%81%E9%81%8D%E5%8E%86%E6%89%80%E6%9C%89%E6%96%87%E4%BB%B6%EF%BC%9F.png)
根据我的理解,当用于du
获取文件夹的总大小时,该命令会枚举每个(子)文件夹中的每个文件并将其相加。
yann@p:~$ du /var/log
4 /var/log/ntpstats
...
148 /var/log/apt
564 /var/log/installer
8 /var/log/cups
91748 /var/log
但是,该命令如何df
立即返回结果,例如
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda1 35209808 18707476 14694008 57% /
无需枚举驱动器上的所有文件?
如果有一种快速的方法来了解整个驱动器上的已用空间,那么为什么没有快速的方法来了解文件夹的大小呢?或者有吗?
提前致谢。
答案1
df
使用statvfs()
系统调用并向文件系统询问当前空间统计信息。这当然很快,因为文件系统在管理文件系统时始终跟踪文件系统上使用的空间。
因此,速度快的原因df
是使用来自文件系统的预先计算的缓存值。
这是历史:
在 20 世纪 70 年代,df
出现了一个 suid root 程序,它确实访问原始磁盘设备并从超级块获取文件系统统计信息。
在 20 世纪 80 年代中期,SunOS 引入了系统调用statfs()
以及第一个 VFS 实现。此呼叫不再需要特权。该接口已在 Tahoe 会议上上次 SunOS/BSD 代码交换期间提供给 *BSD。
1989 年,SVr4/Solaris 引入了增强的 VFS 接口,将系统调用重命名为statvfs().
此版本的系统调用已添加到 POSIX,各种操作系统从该接口复制了该接口。
由于df
数据是从仅具有整个文件系统值的超级块间接获取的,因此没有快速的方法来获取单个目录的数字。
答案2
作为正常操作的一部分,文件系统可能会保留已使用和空闲数据块的计数。df
使用此信息。
即使文件系统不保留实时计数器,在写入新数据时也需要一种快速的方法来查找空闲块,并且相同的数据也可以用于查找空闲块的数量。
理论上,某些文件系统也可以在每个目录的基础上保留这样的已用空间计数器。然而,也存在一些问题。
如果递归地保留整个子树的计数,文件系统将需要将使用数量向上传播到任意深度。这可能会减慢所有写入操作的速度。如果仅保留目录中紧邻的文件,则仍然需要对树进行递归遍历才能找到树的总大小。
在类 Unix 文件系统上,硬链接是一个更大的障碍。当一个文件可以从多个目录(或从同一个目录多次)链接到时,它没有唯一的父目录。文件的大小应该在哪里计算?在链接到它的所有目录中进行计算会导致总使用量虚高,因为该文件可以被计算多次。仅在一个目录中进行计算显然也是错误的。
事实上,传统 Unix 文件系统上的文件(即索引节点)甚至不知道它们所在的目录,只知道它们的链接数(它们拥有的名称)。在大多数使用中,不需要该信息,因为无论如何文件主要是通过名称来访问的。存储它还需要在索引节点中存储任意数量的数据,从而复制目录中的数据。