11.8.1 切割文件名與路徑
如下代碼是一段文件路徑切割實現,通過傳入文件路徑,獲取文件名和文件路徑的功能。具體實現包括兩個函數:GetFileName
和GetFilePath
。前者接收一個文件路徑字符串,並返回該文件路徑中的文件名;後者接收一個文件路徑字符串,並返回該文件路徑中除文件名以外的部分,即文件路徑。
在main
函數中,首先定義了兩個文件路徑字符串szPathA
和szPathB
。然後,分別調用GetFileName
和GetFilePath
函數,將它們的返回值保存在指針變量ptr
中,並輸出到控制檯上。最後,程序返回0,結束執行。
#include <iostream>
#include <Windows.h>
#include <string.h>
// 傳入路徑得到文件名
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;
}
傳入一個完整文件路徑,並自動分割;
11.8.2 遍歷目錄下文件
如下代碼是一個使用遞歸遍歷目錄,並輸出指定格式的文件信息的程序。主要用到了文件操作函數findfirst()
、_findnext()
和_findclose()
,以及結構體類型_finddata_t
。
findfirst函數是Windows
平臺上用於查找文件的函數之一,它屬於 C Runtime Library(CRT)
中的一部分,提供了一種在指定目錄中搜索文件的機制。
定義:
intptr_t _findfirst(
const char *filespec,
struct _finddata_t *fileinfo
);
參數:
- filespec:指定要搜索的文件規範(通配符模式),可以包含路徑信息。
- fileinfo:指向 finddata_t 結構的指針,用於存儲找到的文件信息。
返回值:
- 如果成功,返回一個查找句柄(handle);如果失敗,返回 -1。
findnext函數是Windows
平臺上用於查找文件的函數之一,它通常與_findfirst
配合使用,用於獲取指定目錄中的下一個文件。
定義:
int _findnext(
intptr_t handle,
struct _finddata_t *fileinfo
);
參數:
- handle:由
findfirst
返回的查找句柄。 - fileinfo:指向
finddata_t
結構的指針,用於存儲找到的下一個文件的信息。
返回值:
- 如果成功,返回 0;如果失敗或到達目錄尾部,返回 -1。
函數dfsFolder()
分別接收目錄路徑和需要查找的文件格式。通過使用_findfirst()
找到該路徑下的第一個文件或文件夾,如果是文件夾,則遞歸調用dfsFolder()
函數,如果是文件,則判斷其是否爲需要查找的格式,如果是則輸出該文件的相關信息。
函數dfsFolderAll()
只傳入了一個參數,即目錄路徑。該函數使用了和dfsFolder()
類似的方法,但是不判斷文件格式,而是將該路徑下的所有文件和文件夾都列出來,在main()
函數中,可以通過調用這兩個函數來實現列出目錄下所有文件和文件夾,或是列出目錄下所有指定格式的文件。
#include <io.h>
#include <iostream>
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;
}
運行後輸出所有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
);
參數:
- lpSystemTime:指向 SYSTEMTIME 結構體的指針,表示待轉換的系統時間。
- lpFileTime:指向 FILETIME 結構體的指針,用於存儲轉換後的文件時間。
返回值:
- 如果函數成功,返回非零值;如果函數失敗,返回零。可以通過調用 GetLastError 函數獲取更多信息。
LocalFileTimeToFileTime 用於將本地時間(FILETIME 結構體表示)轉換爲協調世界時(UTC)時間(同樣是 FILETIME 結構體表示)。
函數簽名:
BOOL LocalFileTimeToFileTime(
const FILETIME *lpLocalFileTime,
LPFILETIME lpFileTime
);
參數:
- lpLocalFileTime:指向 FILETIME 結構體的指針,表示待轉換的本地時間。
- lpFileTime:指向 FILETIME 結構體的指針,用於存儲轉換後的 UTC 時間。
返回值:
- 如果函數成功,返回非零值;如果函數失敗,返回零。可以通過調用 GetLastError 函數獲取更多信息。
SetFileTime 用於設置指定文件的創建時間、訪問時間和修改時間。
函數簽名:
BOOL SetFileTime(
HANDLE hFile,
const FILETIME *lpCreationTime,
const FILETIME *lpLastAccessTime,
const FILETIME *lpLastWriteTime
);
參數:
- hFile:要設置時間信息的文件的句柄。
- lpCreationTime:指向 FILETIME 結構體的指針,表示文件的創建時間。
- lpLastAccessTime:指向 FILETIME 結構體的指針,表示文件的最後訪問時間。
- lpLastWriteTime:指向 FILETIME 結構體的指針,表示文件的最後修改時間。
返回值:
- 如果函數成功,返回非零值;如果函數失敗,返回零。可以通過調用 GetLastError 函數獲取更多信息。
#include <io.h>
#include <iostream>
#include <windows.h>
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;
}
運行後,目錄下的文件將被重置時間戳;