• 11.8 实现重置文件时间戳


    11.8.1 切割文件名与路径

    如下代码是一段文件路径切割实现,通过传入文件路径,获取文件名和文件路径的功能。具体实现包括两个函数:GetFileNameGetFilePath。前者接收一个文件路径字符串,并返回该文件路径中的文件名;后者接收一个文件路径字符串,并返回该文件路径中除文件名以外的部分,即文件路径。

    main函数中,首先定义了两个文件路径字符串szPathAszPathB。然后,分别调用GetFileNameGetFilePath函数,将它们的返回值保存在指针变量ptr中,并输出到控制台上。最后,程序返回0,结束执行。

    #include 
    #include 
    #include 
    
    // 传入路径得到文件名
    char* GetFileName(char* Path)
    {
        if (strchr(Path, '\\'))
        {
            char ch = '\\';
            char* ref = strrchr(Path, ch) + 1;
            return ref;
        }
        else
        {
            char ch = '/';
            char* ref = strrchr(Path, ch) + 1;
            return ref;
        }
    }
    
    // 传入路径只得到文件路径
    char* GetFilePath(char *Path)
    {
        int i, pos;
        for (int count = 0; count < strlen(Path); count++)
        {
            if (Path[count] == '\\' || Path[count] == '/')
            {
                pos = count;
            }
        }
        Path[pos] = '\0';
        return Path;
    }
    
    int main(int argc,char *argv[])
    {
        char szPathA[128] = "C://Windows/LanguageOverlayCache/server.cpp";
        char szPathB[128] = "c:\\Windows\\LanguageOverlayCache\\kernel.dll";
        char* ptr = NULL;
    
        ptr = GetFileName(szPathA);
        std::cout << "文件名A: " << ptr << std::endl;
    
        ptr = GetFileName(szPathB);
        std::cout << "文件名B: " << ptr << std::endl;
    
        ptr = GetFilePath(szPathB);
        std::cout << "文件路径: " << ptr << std::endl;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    传入一个完整文件路径,并自动分割;

    11.8.2 遍历目录下文件

    如下代码是一个使用递归遍历目录,并输出指定格式的文件信息的程序。主要用到了文件操作函数findfirst()_findnext()_findclose(),以及结构体类型_finddata_t

    findfirst函数是Windows平台上用于查找文件的函数之一,它属于 C Runtime Library(CRT)中的一部分,提供了一种在指定目录中搜索文件的机制。

    定义:

    intptr_t _findfirst(
        const char *filespec,
        struct _finddata_t *fileinfo
    );
    
    • 1
    • 2
    • 3
    • 4

    参数:

    • filespec:指定要搜索的文件规范(通配符模式),可以包含路径信息。
    • fileinfo:指向 finddata_t 结构的指针,用于存储找到的文件信息。

    返回值:

    • 如果成功,返回一个查找句柄(handle);如果失败,返回 -1。

    findnext函数是Windows平台上用于查找文件的函数之一,它通常与_findfirst配合使用,用于获取指定目录中的下一个文件。

    定义:

    int _findnext(
        intptr_t handle,
        struct _finddata_t *fileinfo
    );
    
    • 1
    • 2
    • 3
    • 4

    参数:

    • handle:由findfirst返回的查找句柄。
    • fileinfo:指向finddata_t结构的指针,用于存储找到的下一个文件的信息。

    返回值:

    • 如果成功,返回 0;如果失败或到达目录尾部,返回 -1。

    函数dfsFolder()分别接收目录路径和需要查找的文件格式。通过使用_findfirst()找到该路径下的第一个文件或文件夹,如果是文件夹,则递归调用dfsFolder()函数,如果是文件,则判断其是否为需要查找的格式,如果是则输出该文件的相关信息。

    函数dfsFolderAll()只传入了一个参数,即目录路径。该函数使用了和dfsFolder()类似的方法,但是不判断文件格式,而是将该路径下的所有文件和文件夹都列出来,在main()函数中,可以通过调用这两个函数来实现列出目录下所有文件和文件夹,或是列出目录下所有指定格式的文件。

    #include 
    #include 
    
    using namespace std;
    
    // 列举出所有文件路径
    void dfsFolderAll(string folderPath)
    {
        _finddata_t file;
        int k;
        long HANDLE;
        k = HANDLE = _findfirst(folderPath.c_str(), &file);
        while (k != -1)
        {
            cout << file.name << endl;
            k = _findnext(HANDLE, &file);
        }
        _findclose(HANDLE);
    }
    
    // 传入目录与需要列出的指定格式文件
    void dfsFolder(string folderPath,string subpath)
    {
        _finddata_t FileInfo;
        /*  文件信息结构体
        struct _finddata_t{
             unsigned attrib;     // 文件属性
             time_t time_create;    // 创建时的时间戳
             time_t time_access;    // 最后一次被访问时的时间戳
             time_t time_write;     // 最后一次被修改时的时间戳
             _fsize_t size;       // 文件字节大小
             char name[_MAX_FNAME];   // 文件名
        };*/
        string strfind = folderPath + "\\*";
        long Handle = _findfirst(strfind.c_str(), &FileInfo);
    
        if (Handle == -1L)
        {
            exit(0);
        }
        do
        {
            // 判断是否为目录 
            if (FileInfo.attrib & _A_SUBDIR)
            {
                // 判断目录是否为当前目录和上一级目录
                if ((strcmp(FileInfo.name, ".") != 0) && (strcmp(FileInfo.name, "..") != 0))
                {
                    // 如果不是则拼接当前路径继续递归调用
                    string newPath = folderPath + "\\" + FileInfo.name;
                    dfsFolder(newPath,subpath.c_str());
                }
            }
            else
            {
                // 判断是不是指定后缀的文件
                if (strstr(FileInfo.name, subpath.c_str()))
                {
                    cout << " 文件名: " << FileInfo.name << " 文件大小: " << FileInfo.size;
            if (FileInfo.attrib == _A_NORMAL)
            {
                        cout << " 普通文件 " << endl;
            }
            else if (FileInfo.attrib == _A_RDONLY)
            {
              cout << " 只读文件 " << endl;
            }
            else if (FileInfo.attrib == _A_HIDDEN)
            {
              cout << " 隐藏文件 " << endl;
            }
            else if (FileInfo.attrib == _A_SYSTEM)
            {
              cout << " 系统文件 " << endl;
            }
            else if (FileInfo.attrib == _A_SUBDIR)
            {
              cout << " 子目录 " << endl;
            }
            else
            {
              cout << " 存档文件 " << endl;
            }
                }
            }
        } while (_findnext(Handle, &FileInfo) == 0);
        _findclose(Handle);
    }
    
    int main(int argc,char *argv[])
    {
        //dfsFolder("C:\\Windows\\system32",".dll");
        dfsFolderAll("C:\\Windows\\system32\\*");
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    运行后输出所有C:\\Windows\\system32\\*目录下的文件;

    11.8.3 重置文件目录时间戳

    文件目录时间戳是指与文件或目录相关联的时间信息,通常包括三个主要的时间戳:

    • 创建时间(Creation Time): 表示文件或目录被创建的时间。这个时间戳记录了文件或目录在文件系统中第一次被创建的时间点。
    • 最后访问时间(Last Access Time): 表示文件或目录最后一次被访问的时间。每当文件或目录被打开、读取、执行等操作时,最后访问时间都会更新。
    • 最后修改时间(Last Write Time): 表示文件或目录最后一次被修改的时间。当文件内容发生变化、文件被写入时,最后修改时间会更新。

    这些时间戳提供了关于文件或目录的重要信息,对于文件管理和调查文件活动非常有用。在Windows和许多其他操作系统中,这些时间戳通常以 FILETIME 结构体的形式存储,该结构体表示从1601年1月1日午夜开始计算的100纳秒间隔数。

    这些时间戳可以通过文件系统或相关的系统调用函数(如 GetFileTime、SetFileTime)来访问和修改。

    SystemTimeToFileTime 用于将SYSTEMTIME结构体表示的时间转换为FILETIME结构体表示的时间。

    函数签名:

    BOOL SystemTimeToFileTime(
      const SYSTEMTIME *lpSystemTime,
      LPFILETIME       lpFileTime
    );
    
    • 1
    • 2
    • 3
    • 4

    参数:

    • lpSystemTime:指向 SYSTEMTIME 结构体的指针,表示待转换的系统时间。
    • lpFileTime:指向 FILETIME 结构体的指针,用于存储转换后的文件时间。

    返回值:

    • 如果函数成功,返回非零值;如果函数失败,返回零。可以通过调用 GetLastError 函数获取更多信息。

    LocalFileTimeToFileTime 用于将本地时间(FILETIME 结构体表示)转换为协调世界时(UTC)时间(同样是 FILETIME 结构体表示)。

    函数签名:

    BOOL LocalFileTimeToFileTime(
      const FILETIME *lpLocalFileTime,
      LPFILETIME     lpFileTime
    );
    
    • 1
    • 2
    • 3
    • 4

    参数:

    • lpLocalFileTime:指向 FILETIME 结构体的指针,表示待转换的本地时间。
    • lpFileTime:指向 FILETIME 结构体的指针,用于存储转换后的 UTC 时间。

    返回值:

    • 如果函数成功,返回非零值;如果函数失败,返回零。可以通过调用 GetLastError 函数获取更多信息。

    SetFileTime 用于设置指定文件的创建时间、访问时间和修改时间。

    函数签名:

    BOOL SetFileTime(
      HANDLE      hFile,
      const FILETIME *lpCreationTime,
      const FILETIME *lpLastAccessTime,
      const FILETIME *lpLastWriteTime
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    参数:

    • hFile:要设置时间信息的文件的句柄。
    • lpCreationTime:指向 FILETIME 结构体的指针,表示文件的创建时间。
    • lpLastAccessTime:指向 FILETIME 结构体的指针,表示文件的最后访问时间。
    • lpLastWriteTime:指向 FILETIME 结构体的指针,表示文件的最后修改时间。

    返回值:

    • 如果函数成功,返回非零值;如果函数失败,返回零。可以通过调用 GetLastError 函数获取更多信息。
    #include 
    #include 
    #include 
    
    using namespace std;
    
    // 修改文件当前创建日期
    bool SetLocalFileTime(const char* FilePath, const char* Date, const char* Time)
    {
        HANDLE hFile = CreateFileA(FilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
        {
            return false;
        }
    
        SYSTEMTIME spec_time;
        sscanf(Date, "%d-%d-%d", &spec_time.wYear, &spec_time.wMonth, &spec_time.wDay);
        sscanf(Time, "%d:%d:%d", &spec_time.wHour, &spec_time.wMinute, &spec_time.wSecond);
    
        FILETIME ft, LocalFileTime;
        SystemTimeToFileTime(&spec_time, &ft);
        LocalFileTimeToFileTime(&ft, &LocalFileTime);
    
        if (SetFileTime(hFile,
            &LocalFileTime,    // 创建时间
            &LocalFileTime,    // 访问时间
            &LocalFileTime     // 修改时间
            ))
        {
            CloseHandle(hFile);
            return true;
        }
        CloseHandle(hFile);
        return false;
    }
    
    // 批量修改文件名
    void BatchSetFileDateTime(string folderPath, string Date, string Time)
    {
        _finddata_t FileInfo;
        string strfind = folderPath + "\\*";
        long Handle = _findfirst(strfind.c_str(), &FileInfo);
    
        if (Handle == NULL)
        {
            exit(0);
        }
        do
        {
            // 判断是否为目录 
            if (FileInfo.attrib & _A_SUBDIR)
            {
                // 判断目录是否为当前目录和上一级目录
                if ((strcmp(FileInfo.name, ".") != 0) && (strcmp(FileInfo.name, "..") != 0))
                {
                    // 如果不是则拼接当前路径继续递归调用
                    string newPath = folderPath + "\\" + FileInfo.name;
                    bool ref = SetLocalFileTime(newPath.c_str(), Date.c_str(), Time.c_str());
                    if (ref == true)
                    {
                        std::cout << "[*] 目录: " << newPath.c_str() << std::endl;
                    }
                    BatchSetFileDateTime(newPath, Date, Time);
                }
            }
            else
            {
                string newPath = folderPath + "\\" + FileInfo.name;
                bool ref = SetLocalFileTime(newPath.c_str(), "1995-01-01", "12:00:00");
                if (ref == true)
                {
                    std::cout << "[*] 文件: " << newPath.c_str() << std::endl;
                }
            }
    
        } while (_findnext(Handle, &FileInfo) == 0);
        _findclose(Handle);
    }
    
    int main(int argc, char* argv[])
    {
        BatchSetFileDateTime("D:\\lyshark", "1995-01-01", "0:0:0");
    
        system("pause");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    运行后,目录下的文件将被重置时间戳;

  • 相关阅读:
    Kafka内外网分流配置listeners和advertised.listeners
    【算法与数据结构】501、LeetCode二叉搜索树中的众数
    Java main方法的形参 和 方法的可变参数
    Vue2里监听localstorage里值的变化
    # [AI]多模态聚类能力助力AI完成自主意识测试
    Radis基础命令(Hash类型)对field进行的操作
    【linux基础】linux中文件权限的含义并修改
    Pandas数据分析:处理文本数据(str/object)各类操作+代码一文详解(二)
    Flink系列文档-(YY02)-Flink编程基础-入门示例
    【SLAM中的问题相关解决方案】
  • 原文地址:https://blog.csdn.net/lyshark_csdn/article/details/134499524