03-文件时间戳
15.2 文件时间戳
stat结构的st_atime、st_mtime和st_ctime字段所含为文件时间戳,分别记录了对文件的上次访问时间、上次修改时间,以及文件状态(即文件i节点内信息)上次发生变更的时间。对时间戳的记录形式为自1970年1月1日(参见10.1节)以来所历经的秒数。
大多数原生Linux和UNIX文件系统都支持上述所有的时间戳字段,但某些非UNIX文件系统则未必如此。
表15-2总结了本书所述各种系统调用及库函数所改变的相应时间戳字段(有时则是指父目录的类似字段)。本表标题中的a、m和c分别表示st_atime、st_mtime和st_ctime字段。在大多数情况下,系统调用会将相关时间戳置为当前时间。但utime()及类似调用(将在15.2.1和15.2.2节讨论)则不在此列,可利用这些系统调用显式将对文件的上次访问时间和上次修改时间设定为任意值。
| 函 数 | 文件或目录 | 父目录 | 注 释 | | :----- | :----- | :----- | :----- | :----- | :----- | | a | m | c | a | m | c | | chmod() | | | • | | | | 与fchmod()相同 | | chown() | | | • | | | | 与lchown()和fchown()相同 | | exec() | • | | link() | | | • | | • | • | 影响第二个参数的父目录 | | mkdir() | • | • | • | | • | • | | mkfifo() | • | • | • | | • | • | | mknod() | • | • | • | | • | • | | mmap() | • | • | • | | | | 仅当对具有MAP_SHARED属性的映射进行更新时,才会改变 st_mtime和 st_ctime | | msync() | | • | • | | | | 仅当修改文件时,才会改变时间戳 | | open(), creat() | • | • | • | | • | • | 新建文件时 | | open(), creat() | | • | • | | | | 截断现有文件时 | | pipe() | • | • | • | | read() | • | | | | | | 与readv()、pread()和 preadv()相同 | | readdir() | • | | | | | | readdir()可缓冲目录条目,仅当读取目录时,才会更新各时间戳 | | removexattr() | | | • | | | | 与fremovexattr()和removexattr()相同 | | rename() | | | • | | • | • | 同时影响文件(更名前后)的父目录。SUSv3并未强制要求改变文件的st_ctime,只是顺带指出有一些实现是照此办理的 | | rmdir() | | | | | • | • | 与remove(directory)相同 | | sendfile() | • | | | | | | 改变了输入文件的时间戳 | | setxattr() | | | • | | | | 与fsetxattr()和lsetxattr()相同 | | symlink() | • | • | • | | • | • | 设置链接(而非目标文件)的时间戳 | | truncate() | | • | • | | | | 与ftruncate()相同,仅当文件大小改变时,才会改变时间戳 | | unlink() | | | • | | • | • | 与remove(file)相同。若之前的链接计数大于1,会改变文件的st_ctime | | utime() | • | • | • | | | | 与 utimes()、futimes()、futimens()、lutimes()和utimensat()相同 | | write() | | • | • | | | | 与writev()、pwrite()和pwritev()相同 |
本书14.8.1节和15.5节分别介绍了可阻止对文件上次访问时间进行更新的mount(2)选项①,以及作用于单个文件的标志。4.3.1节中介绍的open() O_NOATIME标志也能起到类似作用。由于采用此标志可降低对磁盘的操作次数,提升某些应用的文件访问性能,故而颇具实用价值。
虽然大多数UNIX系统都不会记录文件的创建时间,但最新的BSD系统会使用名为st_birthtime的stat字段来记录这一时间。
纳秒时间戳
对于stat结构所含的3个时间戳字段,Linux从2.6版本将其精度提升至纳秒级。纳秒级分辨率将提高某些程序的精度,因为此类程序需要根据文件时间戳的先后顺序来作决定(比如,make(1))。
SUSv3并未强制要求stat结构对纳秒级时间戳的支持,但SUSv4对此则有明文规定。
并非所有文件系统都支持纳秒级精度的时间戳。JFS、XFS、ext4,以及Btrfs文件系统都支持,但ext2、ext3以及Reiserfs文件系统则不然。
glibc API(自版本2.3起)将每个时间戳字段都定义为timespec结构(本节稍后在介绍utimensat()时将会讲解该结构),此结构是以秒和纳秒为单位来表示时间的一种组件。使用恰当的宏定义,该组件的秒级部分可见诸于传统字段(st_atime、st_mtime,以及st_ctime)中。而对其纳秒级部分的访问则会采用如下手法:通过诸如st_atim.tv_nsec 之类的字段名来获取文件上次访问时间的纳秒级部分。