导读:本期聚焦于会飞的猪创作的《C++如何获取文件创建时间?filesystem::last_write_time用法详解》,敬请观看详情。文件时间戳在很多场景下都需要用到,比如缓存失效判断、日志清理、增量备份等。C++17引入的std::filesystem库提供了跨平台的文件时间操作能力,其中last_write_time函数可以获取和修改文件的最后修改时间。不过很多人会发现一个问题:标准库里并没有直接提供获取文件创建时间的接口,这是不少开发者容易踩坑的地方。本文将详细讲解last_write_time的返回类型file_time_type与系统时钟的转换方法,说明为什么C++标准库没有创建时间的统一接口,并分别给出Windows下GetFileAttributesEx和Linux下stat结构体的具体实现代码,最后提供一个跨平台封装方案,帮助你优雅地拿到文件的各类时间信息。

在写文件管理、缓存清理或者增量同步这类功能时,几乎都会碰到一个问题:怎么用C++拿到一个文件的时间信息。C++17把std::filesystem纳入标准之后,filesystem::last_write_time成了最顺手的工具,但翻开文档你会发现,标准库只给了最后修改时间,压根没有"创建时间"这个接口。这篇文章就把这件事讲透:last_write_time怎么用、返回的时间怎么转换成可读格式、以及在Windows和Linux下分别怎么真正拿到文件的创建时间。

C++如何获取文件创建时间?filesystem::last_write_time用法详解

一、last_write_time的基本用法与返回值处理

last_write_time定义在<filesystem>头文件中,它有两个重载:一个只读,返回文件的最后修改时间;另一个可以传入时间点来修改文件时间。只读版本的签名很简单,传入一个path或者directory_entry,返回一个file_time_type类型的值。

#include <filesystem>
#include <iostream>

namespace fs = std::filesystem;

int main() {
    fs::path p = "test.txt";
    if (!fs::exists(p)) {
        std::cerr << "文件不存在" << std::endl;
        return 1;
    }
    // 获取最后修改时间
    fs::file_time_type ftime = fs::last_write_time(p);
    // 转换为系统时钟时间点
    auto systime = std::chrono::clock_cast<std::chrono::system_clock>(ftime);
    std::time_t tt = std::chrono::system_clock::to_time_t(systime);
    std::cout << "最后修改时间: " << std::ctime(&tt);
    return 0;
}

这里有个关键点:file_time_type的时钟是file_clock,它和system_clock不是同一个时钟,epoch(起始时刻)不同,不能直接拿来当时间戳用。C++20提供了clock_cast来做转换,非常方便。如果你还在用C++17,就得自己算偏移量,常用的写法是利用file_time_type::clock::to_sys,不过这个接口是libc++和部分标准库的扩展,MSVC支持得比较好:

// C++17下的转换写法(MSVC和较新的libstdc++可用)
auto ftime = fs::last_write_time(p);
auto sctp = std::chrono::system_clock::now();
auto fnow = fs::file_time_type::clock::now();
// 用两个时钟的当前时刻做差,抵消epoch差异
auto diff = std::chrono::duration_cast<std::chrono::seconds>(fnow.time_since_epoch())
          - std::chrono::duration_cast<std::chrono::seconds>(sctp.time_since_epoch());
std::time_t tt = std::chrono::system_clock::to_time_t(sctp)
               + diff.count();

除了读,修改时间也是一行代码的事:fs::last_write_time(p, fs::file_time_type::clock::now());就能把文件时间刷成当前时刻,写测试用例的时候特别有用。

二、为什么标准库没有"创建时间"接口

很多人第一反应是这是标准库的缺失,其实这是有意为之的设计。文件创建时间这个概念在不同操作系统上的语义完全不一样:Windows的NTFS会记录真实的创建时间(creation time),而Linux传统的ext系列文件系统只有inode中的ctime(inode状态变更时间)、mtime(内容修改时间)和atime(访问时间),很多发行版甚至默认挂载了noatime选项,连atime都不更新。Linux内核从4.11开始支持create birth time(statx系统调用的STATX_BTIME),但取决于文件系统是否真正记录这个值。

正因为语义不统一,C++标准委员会没有把它放进std::filesystem,否则同一个函数在Linux上返回的可能只是inode变更时间,会产生严重的误导。所以正确的做法是:需要创建时间时,直接调用平台原生API,Windows用GetFileAttributesEx,Linux用statx或stat结构体。

三、Windows下获取文件创建时间

Windows的方案最直接,GetFileAttributesEx一次调用就能拿到创建时间、最后访问时间和最后修改时间三组值,返回的是FILETIME结构,需要转换成Unix时间戳:

#include <windows.h>
#include <ctime>
#include <iostream>

// FILETIME转Unix时间戳
time_t FileTimeToUnix(const FILETIME& ft) {
    ULARGE_INTEGER ull;
    ull.LowPart = ft.dwLowDateTime;
    ull.HighPart = ft.dwHighDateTime;
    // FILETIME以1601-01-01起算,单位100纳秒,与1970相差11644473600秒
    return static_cast<time_t>((ull.QuadPart - 116444736000000000ULL) / 10000000ULL);
}

int main() {
    WIN32_FILE_ATTRIBUTE_DATA info;
    if (GetFileAttributesExA("test.txt", GetFileExInfoStandard, &info)) {
        time_t ct = FileTimeToUnix(info.ftCreationTime);
        std::cout << "创建时间: " << std::ctime(&ct);
    }
    return 0;
}

注意FILETIME的起点是1601年1月1日,和Unix时间戳的1970年差了11644473600秒,这个魔数一定要减,否则时间会差三个多世纪。另外如果文件在FAT32分区上,创建时间的精度只有2秒,做精确比较时要留意。

四、Linux下的stat与statx方案

传统做法是调用stat,拿到的st_ctime是inode变更时间而不是创建时间,这一点务必区分清楚。真正的创建时间要用较新的statx系统调用:

#include <sys/stat.h>
#include <iostream>

int main() {
    struct stat st;
    if (stat("test.txt", &st) == 0) {
        std::cout << "内容修改时间: " << ctime(&st.st_mtime) << std::endl;
        std::cout << "inode变更时间: " << ctime(&st.st_ctime) << std::endl;
    }
    return 0;
}

如果内核版本在4.11以上且文件系统支持(ext4、btrfs、xfs都支持birth time),可以封装一个基于statx的实现,请求STATX_BTIME掩码,从返回的stx_btime字段拿到真实的创建时间。glibc从2.28开始提供了statx的包装函数,直接包含<sys/stat.h>就能用。

五、一套跨平台封装思路

把上面的平台代码用条件编译包起来,对外暴露统一的FileTimeInfo结构体,是工程里最常见的做法。可以配合std::filesystem做路径校验和遍历,时间获取部分按平台分发:

#include <filesystem>
#include <ctime>
#include <optional>

struct FileTimeInfo {
    time_t create_time;   // 创建时间
    time_t modify_time;   // 修改时间
};

std::optional<FileTimeInfo> GetFileTimes(const std::filesystem::path& p) {
    if (!std::filesystem::exists(p)) return std::nullopt;
    FileTimeInfo info{};
#ifdef _WIN32
    WIN32_FILE_ATTRIBUTE_DATA attr;
    if (!GetFileAttributesExA(p.string().c_str(), GetFileExInfoStandard, &attr))
        return std::nullopt;
    ULARGE_INTEGER u;
    u.LowPart = attr.ftCreationTime.dwLowDateTime;
    u.HighPart = attr.ftCreationTime.dwHighDateTime;
    info.create_time = (u.QuadPart - 116444736000000000ULL) / 10000000ULL;
    u.LowPart = attr.ftLastWriteTime.dwLowDateTime;
    u.HighPart = attr.ftLastWriteTime.dwHighDateTime;
    info.modify_time = (u.QuadPart - 116444736000000000ULL) / 10000000ULL;
#else
    struct stat st;
    if (stat(p.string().c_str(), &st) != 0) return std::nullopt;
    info.create_time = st.st_ctime;  // Linux回退为inode变更时间
    info.modify_time = st.st_mtime;
#endif
    return info;
}

这样上层业务代码完全不用关心平台差异。还有一个小建议:如果只是判断文件是否被更新过(比如缓存场景),优先用last_write_time就够了,它的语义在各平台上一致,比创建时间可靠得多。只有用户明确需要"这个文件是什么时候生成的"这种信息时,才去走创建时间的平台API,这样代码的可移植性和正确性都能兼顾。

C++获取文件创建时间filesystem last_write_timeC++17文件时间修改时间:2026-09-13 22:43:00

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260913/56293.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。