You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何仅通过系统调用修改Linux(UNIX)文件单一的最后变更/修改/访问时间?

文件时间戳的系统级修改方案

一、通过系统调用单独修改atime/mtime(无法直接修改ctime)

首先明确三个核心时间戳的特性:

  • atime:文件最后被访问的时间
  • mtime:文件内容最后被修改的时间
  • ctime:文件元数据(权限、所有者、时间戳等)最后被修改的时间,由内核自动维护,任何修改元数据的操作都会触发ctime更新,无常规系统调用可直接修改ctime而不影响其他时间戳

修改atime或mtime的系统调用

Linux下可以通过utimensat(2)或utimes(2)系统调用实现单独修改atime或mtime,而不改动另一个:

  • utimensat是更现代的接口,支持纳秒级时间戳,还可以通过UTIME_OMIT标记保留某一个时间戳不变。
  • 示例C代码片段:
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>

// 仅修改文件的atime为当前时间,保留mtime不变
int update_only_atime(const char *path) {
    struct timespec times[2];
    // 设置atime为当前时间
    times[0].tv_sec = time(NULL);
    times[0].tv_nsec = 0;
    // 标记mtime保持不变
    times[1].tv_sec = UTIME_OMIT;
    times[1].tv_nsec = UTIME_OMIT;
    return utimensat(AT_FDCWD, path, times, 0);
}

// 仅修改文件的mtime为指定时间,保留atime不变
int update_only_mtime(const char *path, time_t mtime_sec) {
    struct timespec times[2];
    // 标记atime保持不变
    times[0].tv_sec = UTIME_OMIT;
    times[0].tv_nsec = UTIME_OMIT;
    // 设置mtime为指定时间
    times[1].tv_sec = mtime_sec;
    times[1].tv_nsec = 0;
    return utimensat(AT_FDCWD, path, times, 0);
}

注意:调用这类系统调用本身会触发ctime更新,因为修改了文件的元数据。

二、工具(touch/debugfs)的实现原理

touch命令

touch的-a(仅改atime)、-m(仅改mtime)选项,底层就是调用utimensat或utimes,通过UTIME_OMIT标记保留不需要修改的时间戳。比如执行touch -m file.txt时,工具会构造times数组,将atime设为UTIME_OMIT,mtime设为目标时间(默认当前时间),然后调用系统完成修改,此时ctime会自动更新为当前时间。

debugfs工具

debugfs是针对ext系列文件系统的底层调试工具,它绕过了常规系统调用,直接挂载文件系统并访问inode的原始数据结构,手动修改inode中存储的atime、mtime、ctime字段。这种方式可以直接修改ctime而不触发内核的自动更新,但属于危险操作,可能破坏文件系统的一致性,仅适合离线修复或特殊场景。

三、atime的性能争议

atime的设计初衷是记录文件访问时间,但每次读取文件都会触发atime更新,带来额外的IO开销,在高并发场景(如Web服务器、缓存服务)中会显著影响性能。因此多数Linux系统默认使用relatime挂载选项(仅当atime早于mtime/ctime时才更新),或直接使用noatime完全禁用atime更新,平衡功能与性能。

内容的提问来源于stack exchange,提问作者tahzibi.jafar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 08:35:38