应先用 f.is_regular_file() 过滤普通文件,再将 last_write_time() 转为 time_t 比较排序,避免目录混入、时钟不兼容和中文路径乱码问题。

用 std::filesystem 获取文件修改时间并排序
标准库从 C++17 开始支持 std::filesystem,它能跨平台读取文件元信息,比手写 stat() 或 Windows API 更简洁。关键不是“怎么取时间”,而是“取完怎么比”——std::filesystem::last_write_time() 返回的是 file_time_type,不能直接用 比较(某些编译器会报错),必须转成统一时钟的 <code>time_point。
实操建议:
- 用
std::filesystem::file_time_type::clock::to_time_t()转成time_t再比较,兼容性最稳 - 别直接对
last_write_time()做减法或比较,不同实现下file_time_type可能对应不同底层时钟 - Windows 上默认返回本地时区时间,Linux/macOS 是 UTC;若需严格按绝对时间排,建议统一转为
time_t或std::chrono::system_clock::time_point
auto tp = std::filesystem::file_time_type::clock::to_time_t(f.last_write_time());
排序时忽略子目录,只排普通文件
遍历 std::filesystem::directory_iterator 默认包含子目录和符号链接,但按修改时间排序通常只关心可读的普通文件。不加过滤会导致结果混入目录项,而目录的 last_write_time() 表示其元数据变更(如新增/删除文件),和用户直觉不符。
常见错误现象:
- 输出里出现空文件名或路径异常 —— 实际是目录被当成文件处理了
- 排序结果和资源管理器显示不一致 —— 因为资源管理器默认不把目录纳入“文件列表”
实操建议:
- 用
f.is_regular_file()过滤,不要只靠扩展名或!f.is_directory() - 加上
f.status().permissions() & std::filesystem::perms::owner_read防止权限不足导致last_write_time()抛异常 - 遇到
std::filesystem::filesystem_error时跳过,避免整个排序中断
降序排序时注意 std::sort 的谓词写法
升序是默认行为,降序容易写反:有人写 a > b 却忘了两个参数顺序,导致排序结果乱序或崩溃。更隐蔽的问题是,把 time_t 差值当布尔值用(比如 return a - b > 0),可能因整数溢出产生未定义行为。
实操建议:
- 明确用
return t1 > t2,其中t1和t2是已转换好的time_t - 不要在谓词里重复调用
last_write_time()和to_time_t()—— 提前缓存到vector<pair time_t>></pair>中再排序,性能更好 - 若用
std::ranges::sort(C++20),可配合std::views::filter和std::views::transform流式处理,但要注意视图延迟求值,错误仍得在遍历时捕获
Windows 下中文路径乱码或 std::filesystem::directory_iterator 失败
MSVC 默认用窄字符接口,传入 UTF-8 字符串(如现代编辑器保存的源码)时,std::filesystem::path 构造可能失败或路径解析错位,表现为迭代器抛 filesystem_error 或跳过文件。
根本原因不是编码本身,而是 Windows API 底层期望宽字符串(wchar_t*),而 std::filesystem 在 MSVC 中对窄字符串的转换策略依赖当前代码页 —— 简体中文系统默认 GBK,UTF-8 字符串会被误解。
实操建议:
- 构造
path时显式用std::wstring:例如std::filesystem::path{L"中文文件夹"} - 读取命令行参数时,用
GetCommandLineW()+CommandLineToArgvW()替代argc/argv - 若必须用
char*输入,先用MultiByteToWideChar(CP_UTF8, ...)转码,再构造path
这个点最容易被忽略:你以为程序逻辑没问题,其实是连路径都没正确加载进来。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











