是否有可以确定文件类型的 stat (在大多数 Unix 系统上都可以找到)的替代方法?手册页说调用 stat 很昂贵,我需要在我的应用程序中经常调用它。
5 回答
另一种方法是fstat()
如果您已经打开了文件(因此您有一个文件描述符)。或者lstat()
,如果您想了解符号链接而不是符号链接指向的文件。
我认为手册页夸大了成本;它并不比任何其他必须将文件名解析为 inode 的系统调用差多少。它比getpid()
; 它的成本低于open()
.
为您提供的“文件类型”stat()
是文件是常规文件还是设备文件或目录之类的东西,以及它的大小和 inode 编号等。如果这是您需要知道的,那么您必须使用stat()
.
如果您真正需要知道的是文件内容的类型——例如文本文件、JPEG 图像、MP3 音频——那么你有两个选择。您可以根据文件扩展名进行猜测(如果它以“.mp3”结尾,则该文件可能包含 MP3 音频),或者您可以使用libmagic,它实际上会打开文件并读取其中的一些内容以找出它是什么。libmagic 方法更昂贵(如果您想避免stat()
,您可能也想避免open()
),但不太容易出错(例如,如果“.mp3”文件实际上是 JPEG 图像)。
在具有某些文件系统的 Linux 下,文件类型(常规、字符设备、块设备、目录、管道、符号链接等)存储在 linux_dirent 结构中,这是内核通过 getdents 系统调用提供应用程序目录条目的内容. 如果您需要的 stat 结构中唯一的东西是文件类型,并且您需要为目录的所有或许多条目获取它,您可以直接使用 getdents(而不是 readdir)并尝试从中获取文件类型,仅当您在 linux_dirent 中发现无效文件类型时才使用 stat。根据您的应用程序的文件系统使用模式,如果您使用的是 Linux,这可能比使用 stat 更快,但在许多情况下 stat 应该很快。
Stat 的速度主要与定位磁盘上要求的数据有关。如果您正在遍历一个目录递归地统计所有文件,那么每个 stat 最终应该总体上相当快,因为在您通过先前调用 stat 向内核询问它之前,获取数据 stat 需要的大部分工作最终都被缓存了. 另一方面,如果您统计在系统中随机分布的相同数量的文件,那么内核可能必须为您要调用 stat 的每个文件从磁盘读取几个目录。
fstat 应该总是非常快,因为内核应该已经在 RAM 中拥有您要求的数据,因为它需要访问它以使文件处于打开状态,并且内核不必遇到麻烦遍历文件名的路径以查看每个组件是在 RAM 中还是在磁盘上,并可能从磁盘中读取目录(但可能不必),只是发现它在 RAM 中具有您要求的数据。
话虽如此,在打开的文件上调用 stat 应该比在未打开的文件上调用它更快。
您知道 *nix 系统上的“魔法”文件吗?通过从命令行查询文件,file myfile.ext
您可以获得真正的文件类型。
这是通过读取文件的内容而不是查看其扩展名来完成的,并且广泛用于 *nix (Linux, Unix, ...) 系统。
如果您的应用程序希望在 Linux 系统上运行,您为什么不尝试 inotify(7)。它肯定比stat
ing 许多文件要快。