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

如何获取目录的最后访问、修改时间戳?C++代码修复求助

修复Windows下C++获取目录时间戳的问题

你的代码在处理普通文件时正常,但处理目录时失效,核心原因是打开目录时没有使用Windows要求的特殊标志。Windows将目录视为特殊的文件对象,必须通过特定参数才能正确打开并读取其时间属性。

问题根源

调用CreateFileA打开目录时,默认参数无法识别目录对象,要么返回INVALID_HANDLE_VALUE,要么即便打开成功也无法读取时间戳。必须添加FILE_FLAG_BACKUP_SEMANTICS标志——这个标志允许系统将目录当作文件对象处理,从而支持后续的GetFileTime调用。

修复方案

修改CreateFileA的调用参数,添加必要的标志和共享权限:

  • 新增FILE_FLAG_BACKUP_SEMANTICS标志到创建参数
  • 放宽共享权限为FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,避免因其他进程访问目录导致打开失败

另外,你的原函数GetLastWriteTimeDirectory仅返回最后写入时间,我把它扩展为支持同时获取创建、访问、写入三种时间戳,更贴合实际需求。

修改后的完整代码

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <strsafe.h>
#include <cstring>

BOOL GetFileTimesDirectory(HANDLE arg_h_file, 
                           LPSTR arg_lpsz_create, DWORD arg_dw_size_create, 
                           LPSTR arg_lpsz_access, DWORD arg_dw_size_access,
                           LPSTR arg_lpsz_write, DWORD arg_dw_size_write) {
    FILETIME ft_CreateTime, ft_AccessTime, ft_WriteTime;
    SYSTEMTIME st_UTC, st_Local;
    DWORD dw_Return;

    // 读取文件/目录的所有时间戳
    if (!GetFileTime(arg_h_file, &ft_CreateTime, &ft_AccessTime, &ft_WriteTime)) {
        return FALSE;
    }

    // 转换创建时间为本地时间
    FileTimeToSystemTime(&ft_CreateTime, &st_UTC);
    SystemTimeToTzSpecificLocalTime(NULL, &st_UTC, &st_Local);
    dw_Return = StringCchPrintfA(arg_lpsz_create, arg_dw_size_create, "%02d/%02d/%d %02d:%02d", 
                                st_Local.wMonth, st_Local.wDay, st_Local.wYear, 
                                st_Local.wHour, st_Local.wMinute);
    if (dw_Return != S_OK) return FALSE;

    // 转换访问时间为本地时间
    FileTimeToSystemTime(&ft_AccessTime, &st_UTC);
    SystemTimeToTzSpecificLocalTime(NULL, &st_UTC, &st_Local);
    dw_Return = StringCchPrintfA(arg_lpsz_access, arg_dw_size_access, "%02d/%02d/%d %02d:%02d", 
                                st_Local.wMonth, st_Local.wDay, st_Local.wYear, 
                                st_Local.wHour, st_Local.wMinute);
    if (dw_Return != S_OK) return FALSE;

    // 转换写入时间为本地时间
    FileTimeToSystemTime(&ft_WriteTime, &st_UTC);
    SystemTimeToTzSpecificLocalTime(NULL, &st_UTC, &st_Local);
    dw_Return = StringCchPrintfA(arg_lpsz_write, arg_dw_size_write, "%02d/%02d/%d %02d:%02d", 
                                st_Local.wMonth, st_Local.wDay, st_Local.wYear, 
                                st_Local.wHour, st_Local.wMinute);
    return (dw_Return == S_OK);
}

bool AttributeDirectoryTimes(const char* arg_path) {
    HANDLE handleFile;
    char bufferCreateTime[MAX_PATH];
    char bufferAccessTime[MAX_PATH];
    char bufferWriteTime[MAX_PATH];
    char pathDirectory[MAX_PATH];
    strcpy(pathDirectory, arg_path);

    // 修改CreateFileA参数,添加目录支持的标志和共享权限
    handleFile = CreateFileA(pathDirectory, 
                            GENERIC_READ, 
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
                            NULL, 
                            OPEN_EXISTING, 
                            FILE_FLAG_BACKUP_SEMANTICS, 
                            NULL);

    if (handleFile == INVALID_HANDLE_VALUE) {
        printf("打开目录失败,错误码:%lu\n", GetLastError()); // 新增错误排查信息
        return false;
    }

    if (GetFileTimesDirectory(handleFile, bufferCreateTime, MAX_PATH, 
                             bufferAccessTime, MAX_PATH, bufferWriteTime, MAX_PATH)) {
        printf("\n\t\t创建时间: \t%s\n", bufferCreateTime);
        printf("\t\t访问时间: \t%s\n", bufferAccessTime);
        printf("\t\t写入时间: \t%s\n", bufferWriteTime);
        CloseHandle(handleFile);
        return true;
    }
    CloseHandle(handleFile);
    return false;
}

int main(int argc, char* argv[]) {
    AttributeDirectoryTimes("C:\\Users\\mkahs\\Desktop\\Sample\\");
    return 0;
}

关键修改点说明

  1. CreateFileA参数调整:
    • FILE_FLAG_BACKUP_SEMANTICS:让系统将目录识别为可操作的文件对象,这是处理目录的核心要求
    • 扩展共享权限:目录通常会被多个进程访问,使用FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE避免打开失败
  2. 函数扩展:将原单时间戳函数改为支持三种时间戳的函数,更实用
  3. 错误排查:添加GetLastError()输出,方便调试打开目录失败的具体原因

额外高效方案

如果仅需要读取目录属性而不需要打开目录对象,也可以使用GetFileAttributesExA函数,代码会更简洁:

WIN32_FILE_ATTRIBUTE_DATA fileAttr;
if (GetFileAttributesExA(arg_path, GetFileExInfoStandard, &fileAttr)) {
    // 直接使用fileAttr.ftCreationTime、fileAttr.ftLastAccessTime、fileAttr.ftLastWriteTime
    // 后续转换为本地时间的逻辑和之前一致
}

这种方式不需要调用CreateFileA,对于仅读取属性的场景效率更高。

内容的提问来源于stack exchange,提问作者user12317345

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 11:27:29