coreutils 中关于文件时间戳有详细的描述。
标准的 POSIX 文件系统为每个文件记录三个核心时间戳:
atime (Access Time): 文件内容最后被访问(读取)的时间戳。
mtime (Modify Time): 文件内容最后被修改(写入)的时间戳。
ctime (Change Time): 文件元信息(如权限、所有者等状态)最后发生变更的时间戳。
此外,部分文件系统(如 ext4, HFS+, APFS)还支持第四个时间戳:
birthtime (Birth Time): 文件创建时的时间戳。根据定义,此时间一旦生成便永不改变。
如何查看文件时间戳?
最直接的方式是使用 stat 命令。通过 stat 命令可以清晰地查看文件的这三个(或四个)时间戳以及所有其他元信息。
# 查看文件详细时间戳信息
$ stat test.sh
File: test.sh
Size: 119 Blocks: 8 IO Block: 4096 regular file
Device: 3eh/62d Inode: 533092 Links: 1
Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2025-11-17 08:44:51.923141001 +0800
Modify: 2025-11-17 08:44:49.406141000 +0800
Change: 2025-11-17 08:44:49.410141000 +0800
Birth: 2025-11-17 08:44:49.406141000 +0800
在 macOS 系统上,默认的 stat 输出格式与 Linux 不同,需要加上 -x 选项来获得类似的格式。
$ stat -x t.py
File: "t.py"
Size: 99 FileType: Regular File
Mode: (0744/-rwxr--r--) Uid: ( 501/ user) Gid: ( 20/ staff)
Device: 1,16 Inode: 22066917 Links: 1
Access: Fri Dec 26 14:59:20 2025
Modify: Fri Dec 26 14:59:19 2025
Change: Tue Dec 30 14:13:52 2025
Birth: Fri Dec 26 14:59:19 2025
深入理解 ctime
ctime 变更的一个典型例子是修改文件权限。更改权限既不访问文件内容(不影响 atime),也不修改文件内容(不影响 mtime),但文件的元信息(权限位)确实发生了变化,因此 ctime 会被更新。另一个常见操作是文件重命名。
文件权限变更示例:
$ chmod 744 test.sh
$ stat test.sh
...
Access: 2025-11-17 08:44:51.923141001 +0800 # atime 未变
Modify: 2025-11-17 08:44:49.406141000 +0800 # mtime 未变
Change: 2025-12-30 14:32:05.633831000 +0800 # ctime 已更新!
Birth: 2025-11-17 08:44:49.406141000 +0800
文件重命名示例:
$ mv test.sh test_new.sh
$ stat test_new.sh
...
Access: 2025-11-17 08:44:51.923141001 +0800 # atime 未变
Modify: 2025-11-17 08:44:49.406141000 +0800 # mtime 未变
Change: 2025-12-30 14:34:10.391609002 +0800 # ctime 已更新!
Birth: 2025-11-17 08:44:49.406141000 +0800
时间戳的更新策略与性能权衡
从理论上讲,对文件进行读、写、属性更改操作会分别实时更新 atime、mtime 和 ctime。但在实际系统中,出于性能考虑,特别是对 atime 的更新,内核采用了延迟或抑制策略。
你可以通过 mount 命令查看文件系统的挂载选项,其中就包含了 atime 的更新策略。
# 查看文件系统挂载选项
$ mount | grep '/dev'
/dev/sdd on / type ext4 (rw,relatime,discard,errors=remount-ro,data=ordered)
# `relatime` 表示“相对访问时间更新”,这是一个兼顾性能与实用性的默认选项。
不同的 atime 挂载选项会带来不同的性能表现:
| 选项 |
含义 |
特点 |
strictatime |
严格访问时间 |
每次读取都更新 atime。最准确,但会带来大量磁盘 I/O,性能最差。 |
relatime |
相对访问时间 |
默认选项。仅在文件被修改后访问,或访问间隔超过一定时间(通常24小时)时才更新 atime。性能与实用性俱佳。 |
noatime |
不更新访问时间 |
完全不更新 atime。能最大程度提升 I/O 性能,但完全丢失了文件的访问记录。 |
nodiratime |
不更新目录访问时间 |
仅对目录禁用 atime 更新。常与 noatime 或 relatime 联用。 |
relatime 是现在大多数 Linux 发行版的默认选择,它的核心逻辑是:
- 如果文件的
atime 比 mtime 或 ctime 更旧,则在访问时更新 atime。
- 即使满足条件1,
atime 的更新频率也有限制(通常至少24小时一次)。
简单来说,除非文件刚被修改过,否则同一个文件的 atime 一天内通常只记录一次最新的访问。
时间戳相关操作命令
1. 查看时间戳
除了 stat 命令,常用的 ls 命令也可以指定查看不同的时间戳。
ls -l:默认显示文件的修改时间 (mtime)。
ls -lu:显示文件的访问时间 (atime)。
ls -lc:显示文件的状态变更时间 (ctime)。
可以使用 --time-style 选项来指定时间的显示格式。
$ ls -lc --time-style=full-iso ./newfile.txt
-rwxrw-rw- 1 root root 0 2025-12-30 15:26:17.965989005 +0800 ./newfile.txt
2. 修改时间戳
使用 touch 命令。该命令不仅能修改已有文件的时间戳,也常用来创建新文件。
基本操作:
# 创建一个新文件,所有时间戳均为当前时间
$ touch newfile.txt
# 将文件的 atime 和 mtime 更新为当前时间
$ touch filename
常用选项:
-a:只更新访问时间 (atime) 为当前时间。
touch -a filename
-m:只更新修改时间 (mtime) 为当前时间。
touch -m filename
-t:将时间戳设置为指定的绝对时间。
# 格式:[[CC]YY]MMDDhhmm[.ss]
$ touch -m -t 2512311200.00 filename # 将 mtime 设为 2025-12-31 12:00:00
# 注意:使用 -t 修改 mtime 或 atime 时,ctime 会被自动更新为“现在”。
-d:使用易读的字符串来设置时间。
touch -d "2 days ago" filename
touch -d "next Friday" filename
touch -d "2023-10-01 14:30:59" filename
-r:参照另一个文件的时间戳进行设置。
touch -r reference_file target_file # 将 target_file 的时间戳设置为与 reference_file 相同
3. 基于时间戳查找文件
find 命令是文件时间筛选的强大工具。
# 查找最近7天内修改过的文件
find /path -mtime -7
# 查找超过30天未被访问的文件(适用于日志清理)
find /path -atime +30
# 查找最近1天内状态(如权限)发生变更的文件
find /path -ctime -1
# 查找比某个文件更新的文件
find . -newer referencefile.txt
# 查找在特定日期之后修改的文件
find /path -newermt '2025-10-01'
4. 复制文件时保留时间戳
使用 cp 命令复制文件时,默认会使用当前时间作为新文件的时间戳。如果需要保留原文件的时间戳,可以使用特定的选项。
$ cp -p source_file dest_file # -p 或 --preserve,保留所有可能属性(包括时间戳、权限等)
$ cp --preserve=timestamps source_file dest_file # 仅保留时间戳属性
掌握文件时间戳的概念和操作,对于系统维护、脚本编写、问题排查乃至数据恢复都非常有帮助。希望这篇指南能帮你理清 atime, mtime, ctime 的区别与联系。想了解更多系统层面的知识,欢迎访问云栈社区进行交流探讨。