大量文件列表的总文件大小

大量文件列表的总文件大小

这个问题与这个问题非常相似:

文件列表的文件大小总和

事实上,我所有的尝试都在这个问题上列出。

不同之处在于我的列表有大量文件(1M+),而这些尝试似乎不适用于这么多条目。

对于statdu我得到了这些错误:

-bash: /usr/bin/stat: Argument list too long
-bash: /usr/bin/du: Argument list too long  

Perl 解决方案似乎可以工作,但速度非常慢,而且我不确定它是否可以处理完整列表或只是崩溃。

有没有任何解决方案不涉及将我的原始文件分成几部分,然后对部分总和进行求和?

答案1

要找出/some/dir/file使用lstat()stat()(如果您想解析符号链接)系统调用完成的文件的大小,系统需要:

  • Lookup的 inode,检查您是否具有对其的读取和搜索访问权限,并获取有关目录内容所在位置的/信息:/
  • 读取其中的内容/并查找some其中的条目(获取其索引节点号)。
  • 就像 for 一样/,查看/some的 inode 以获得许可等。
  • 重复 for/some/dir和 for/some/dir/file
  • /some/dir/file检索的 inode中的大小属性

如果某些路径组件是符号链接,则也需要对其进行解析。

如果涉及 ACL 或其他安全上下文,这将使查找进一步复杂化。进行查找root会绕过其中的一些部分并可能加快该过程。

因此,stat()(或任何查找文件的系统调用)可能是一项成本高昂的操作,特别是如果所有数据(索引节点以及目录和安全属性的内容)没有缓存在内存中并且需要从计算机上的多个位置检索。硬盘。

即使该目录的内容已被缓存,在未索引的大型目录中查找文件的成本也可能相当高。

有用的方法是对文件列表进行排序,以便同一目录中的文件彼此相邻列出,并最大限度地提高在查找特定文件时缓存数据的机会。

您还需要避免运行太多命令,或者在上面做不必要的额外工作。

所以:

LC_ALL=C sort file | perl -lne '$s += -s} END {print $s'

(as root) 可能接近您能够轻松达到的最快速度。

(这里使用stat()系统调用,以便对于符号链接来说,要考虑它们指向的文件的大小)。

有一些方法可以进一步优化它。例如,如果您有:

/some/very/very/deep/dir/structure/with/many/levels/of/subdirs/file1
/some/very/very/deep/dir/structure/with/many/levels/of/subdirs/file2
/some/very/very/deep/dir/structure/with/many/levels/of/subdirs/file3
/some/very/very/deep/dir/structure/with/many/levels/of/subdirs/file4

open() /some/very/very/deep/dir/structure/with/many/levels/of/subdirs一次然后相对于该目录执行一些fstatat()for file1, ...可能会更快,file2以避免每次都必须查找所有这些 dir 组件,但实现这种优化并不是微不足道的(尽管不是那么简单)也很难)。

根据您的数据,也可以进行一些特定的优化。例如,如果一个文件被列出多次,您可以优化第二个和更多的stat()s。如果/foo是 的符号链接,并且下面列出了与 下/bar相同的数千个文件,那么如果您可以意识到它们实际上是相同的文件,则可以优化一些s.与vs相同,.../foo/barstat()/foo/file/foo/./file/bar/../foo/file

相关内容