简单直接的回答是:通常情况下,ls 命令比直接调用 readdir 系统接口要慢,但在某些特定场景下(尤其是默认行为下),ls 可能会显得“快”或响应更快。
这听起来有点矛盾,下面详细解释一下原因,以及为什么你在做性能对比时可能会感到困惑。
readdir 是 Linux/Unix 系统编程中的一个函数(属于 C 标准库或系统调用),用于读取目录的内容。
ls 命令:它的底层实现其实也是调用了 readdir(或者更现代的 getdents 系统调用)来获取文件列表。ls 只是单纯地列出文件名(例如 ls -f),它的速度应该和直接写 C 代码调用 readdir 差不多,因为底层干的是同一件事。ls 通常比 readdir 慢?ls 命令默认不仅仅做“读取目录”这一件事。它为了提供更好的用户体验,默认会做很多额外的工作,这些工作会消耗大量时间:
ls 默认会按照字母顺序对文件名进行排序。如果目录下有 10 万个文件,排序会消耗大量 CPU 时间。而 readdir 读取出来的顺序通常是文件系统存储的顺序(通常是乱序的),不需要排序。ls 默认会尝试获取每个文件的详细信息(权限、所有者、大小、修改时间等)。这需要调用 stat 系统调用。
stat 调用可能会非常慢。ls 需要显示颜色(通过 --color 选项,通常是默认开启的),它也必须对每个文件调用 stat 来判断文件类型(可执行、目录、软链接等)。ls 需要处理复杂的显示逻辑。ls 感觉比 readdir 快?这是一个常见的“错觉”,通常出现在目录非常大的情况下。
ls 的缓冲与输出优化:ls 命令在输出到终端时,通常会进行行缓冲或全缓冲,并且会优化列对齐。readdir 程序的实现:如果你自己写了一个简单的 C 程序调用 readdir 并 printf 输出,你可能没有做缓冲优化,或者你在循环中做了太多其他事情(比如 sleep 或者复杂的字符串处理)。ls -f 的魔法:如果你运行 ls -f(不排序,不装饰,直接输出),你会发现它瞬间就完成了,比很多简单的 readdir 脚本还要快,因为 ls 是高度优化的二进制程序。假设我们有一个包含 10 万个文件的目录。
| 场景 | 命令/操作 | 速度 | 原因 |
|---|---|---|---|
| 纯读取 (最快) | ls -f 或 ls -U |
极快 | 只调用 readdir,不排序,不 stat。 |
| 纯读取 (代码) | 简单的 C 程序/readdir |
极快 | 和 ls -f 底层一样。 |
默认 ls |
ls |
慢 | 需要排序 + 调用 stat 获取信息 + 颜色判断。 |
默认 ls (管道) |
`ls | cat` | 快 |
readdir + 排序 |
自己写的代码 + qsort |
慢 | 如果你在代码里加了排序,速度会和 ls 一样慢。 |
这是 Debian/Ubuntu 系统上一个非常常见的坑。
ls 或 readdir 时,如果目录很大,速度可能很慢,因为数据需要从磁盘读取。ls 或 readdir 时,速度会极快,因为 Linux 内核会将目录结构和文件元数据缓存到内存中(dentry cache 和 inode cache)。readdir 和 ls 的底层读取速度没有区别。readdir(或 find . -maxdepth 1)比默认的 ls 快,因为 ls 默认要排序和获取文件详情。ls -f(不排序),它和 readdir 一样快。readdir 并且做了排序或 stat,那它就会和 ls 一样慢。建议:
如果你在写脚本或程序,需要快速获取文件名列表,请使用 ls -f 或者 find . -maxdepth 1 -printf '%f\n',或者在 C 代码中使用 readdir 但不要调用 stat。