C 编程/POSIX 参考/sys/stat.h/stat
stat()
是一个 Unix 系统调用,它返回有关文件 inode 的有用数据。stat()
的语义在不同的 操作系统 之间有所不同。例如,Unix 命令 ls 使用它来检索有关(除许多其他信息外)的信息
- mtime: 时间 最后修改(
ls -l
), - ctime: 最后状态更改时间(
ls -lc
)和 - atime: 最后访问时间(
ls -lu
)。
在所有符合 POSIX 标准的 类 Unix 操作系统上都可以找到的 POSIX 库头文件 sys/stat.h
声明了 stat()
、fstat()
和 lstat()
例程
int stat(const char *filename, struct stat *buf);
int lstat(const char *filename, struct stat *buf);
int fstat(int filedesc, struct stat *buf);
并定义了 struct stat
结构,其中至少包含以下成员
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of blocks allocated */
lstat()
是一个 库函数,它检索 文件 的状态。它与 stat()
相同,不同之处在于当文件是 符号链接 时,它返回有关链接本身的信息,而不是链接到的文件的信息。
fstat()
是一个 库函数,它检索文件的狀態。它与 stat()
相同,不同之处在于文件的标识作为 文件描述符 而不是作为 文件名 传递。
写入文件会更改其 mtime
和 ctime
,而读取文件会更改其 atime
。因此,在符合 POSIX 标准的系统上,读取文件会导致写入,这一点受到了批评。这种行为通常可以通过在 /etc/fstab 中添加一个挂载选项来禁用。
但是,关闭 atime 更新会破坏 POSIX 兼容性,并且一些应用程序(尤其是 mutt 邮件阅读器(在某些配置中)和一些文件使用监视工具,尤其是 tmpwatch)也会因此而无法正常工作。在最坏的情况下,不更新 atime 会导致某些备份程序无法备份文件。
Linux 内核开发人员 Ingo Molnár 将 atime 称为“可能是历史上最愚蠢的 Unix 设计理念”,[1][2] 并补充道:“想一想:‘对于从磁盘读取的每个文件,让我们执行...写入磁盘!并且,对于已经缓存并从缓存中读取的每个文件...执行写入磁盘!’”他还强调了这种性能影响
- Atime 更新是 Linux 今天面临的最大的 IO 性能缺陷。摆脱 atime 更新将比过去 10 年所有页面缓存加速的总和,_加在一起_,为我们带来更多日常的 Linux 性能。
当前版本的 Linux、Mac OS X、Solaris、FreeBSD、NetBSD 和 OpenBSD 支持 noatime
挂载选项,该选项会导致 atime 字段永远不会被更新。这会破坏与 POSIX 的兼容性。
当前版本的 Linux 支持四个挂载选项,可以在 fstab 中指定
strictatime
(以前是 atime,以前是默认值;从 2.6.30 开始是 strictatime)– 始终更新 atime。relatime
–(相对 atime),在 2.6.20 中引入,从 2.6.30 开始是默认值nodiratime
– 永远不要更新目录的 atimenoatime
– 永远不要更新 atime;包括 nodiratime;最高性能,最低兼容性
strictatime
符合 POSIX 标准;Alan Cox 将其他选择描述为
- 关闭 atime,它与标准不兼容,切换到 relatime,它与标准不兼容,但不会破坏任何东西(这很好)
使用 noatime
选项挂载的文件系统不会在读取时更新 atime,而 relatime
选项仅在先前 atime 早于 mtime 或 ctime 或者先前 atime 超过 24 小时之前时才会更新 atime。许多用户使用 noatime
没有任何问题,只要他们不使用依赖 atime 的应用程序,并且这比 relatime
提供了一些好处(读取时永远不会写入 atime)。
从 2.6.30(2009 年 6 月 9 日)开始,Linux 默认使用 relatime
,[3] 这样它就不会在所有文件读取时更新 atime。这种行为为大多数用途提供了足够的性能,并且不应破坏任何重要的应用程序。在做出决定之前,对文件系统性能进行了扩展讨论。[4] 事实上,relatime
默认是 Linux 在 2.6.29 版本发布后应用的首个补丁。在最初的补丁中,relatime
仅在 atime < mtime 或 atime < ctime 时更新 atime;后来进行了修改,以更新 24 小时或更长时间之前的时间,以便 tmpwatch 和 Debian 的流行度计数器(popcon)能够正常运行。
请注意,ctime
与文件创建时间无关。它在每次文件内容更改时(与 mtime
同时)更新,以及在元数据更改时更新,例如文件权限、文件所有权以及硬链接的创建和删除。在某些实现中,ctime
会因文件重命名而受到影响(原始 Unix 和现代 Linux 都倾向于这样做)。
与 atime
和 mtime
不同,ctime
无法通过 utime()
设置(如 touch
所使用的);唯一能将其设置为任意值的方法是更改系统时钟。
time_t 提供精确到 1 秒的时间。
某些文件系统提供更高的粒度。在 Linux 内核 2.5.48 及以上版本中,stat 结构支持三个文件时间戳字段的纳秒级分辨率。这些以 stat 结构中的附加字段形式公开。
FAT 文件系统提供的 timestamps 粒度为 2 秒。[7]
- ↑ Kernel Trap: Linux: Replacing atime With relatime,由 Jeremy 于 2007 年 8 月 7 日撰写
- ↑ Once upon atime,LWN,由 Jonathan Corbet 于 2007 年 8 月 8 日撰写
- ↑ Linux 2 6 30,Linux 内核新手
- ↑ That massive filesystem thread,LWN,由 Jonathan Corbet 于 2009 年 3 月 31 日撰写
- ↑ Installing Linux on USB – Part 4: noatime and relatime mount options
- ↑ Relatime Recap,Valerie Aurora
- ↑ How accurate is ruby mtime and friends at StackOverflow.com