引言:
對於大多數的IT企業和絕大多數的個人用戶而言,數據的備份主要是對 數據內容的簡單備份,而很少涉及對備份數據自身屬性如文件屬性、所在文件夾的時間屬 性等內容的備份。而在某些對數據管理有著非常嚴格要求的特殊行業中,對以上這些相關 屬性信息的備份也是同等重要的。但是在目前的Windows操作系統下,不論是直接通過手 工進行數據備份還是通過某些數據備份軟件來進行,都難以將這些信息完全保持原貌復制 過來,尤其對於每時每刻均在發生變化的時間屬性更是難以保持其原始信息。不僅如此, 在Windows操作系統下甚至沒有提供能直接修改此類屬性的工具和手段。為此,筆者對該 問題做了研究,並總結出一套比較簡單的解決辦法。其中,對於文件屬性的備份與更改方 法筆者已在電腦報天極網《在VC++下對文件屬性的獲取與更改》一文做了闡述,因此,本 文在此就不再加以贅述,而著重對文件夾時間屬性的獲取與更改方法進行介紹。
設計思路
在Windows操作系統下並沒有提供任何可供修改文件夾時間屬性的方法和 手段,即使是在Win32 API函數中,也只是提供了對文件時間屬性進行修改的函數調用, 而沒有關於文件夾時間屬性修改的只言片語。雖然Windows所提供的備份程序能夠把待備 份文件夾下的所有子文件夾的時間屬性按照原樣完整的復制過去,但是卻無法保持根目錄 時間屬性的恆定。由此,可以考慮采取備份的方式來進行,並從同備份相關的Win32 API 函數入手。具體而言,可以先以打開文件的方式來打開文件夾,然後就可以通過原本用於 處理文件時間屬性的Win32 API函數GetFileTime()和SetFileTime()來獲取原始時間屬性 並以其為參數來設置備份後的文件夾時間屬性了,這樣的處理可以確保文件夾在備份前後 時間屬性的一致。
根據前面的分析可以看出,按照打開文件的方式來打開文件夾 是整個處理過程的關鍵,通常主要用於創建、打開文件的Win32 API函數CreateFile()並 非只能用來創建和打開文件對象,實際上它還可以用來創建、打開管道、郵槽、通訊資源 、磁盤驅動器(只對Windows NT而言)、控制台和文件夾(只能打開)等。下面給出 CreateFile()的原型:
HANDLE CreateFile( LPCTSTR lpFileName, // 文件名 指針
DWORD dwDesiredAccess, // 訪問模式
DWORD dwShareMode, // 共 享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, //安全屬性
DWORD dwCreationDisposition, // 創建方式
DWORD dwFlagsAndAttributes, // 文件屬性
HANDLE hTemplateFile // 指向待復制屬性的文件指針
);
當用其進行文件夾打開操作時,第一個參數lpFileName應被設置成為 待打開的文件夾的名稱;至於訪問模式可以根據需要靈活設置,對於本文而言,對源文件 夾只進行讀取操作故可以設置為GENERIC_READ,對於備份後的文件夾由於需要將屬性信息 寫入,因此需要有GENERIC_WRITE的支持;共享模式參數dwShareMode的設置與進行文件處 理時的設置沒有什麼區別,在此可以設置為FILE_SHARE_READ|FILE_SHARE_DELETE;由於 CreateFile()函數在進行文件夾操作時,不能以創建方式進行,因此創建方式只能打開已 經存在的對象,即dwCreationDisposition應當設置為OPEN_EXISTING;相比而言, dwFlagsAndAttributes參數的設置是比較重要的,正是通過將該參數設置為 FILE_FLAG_BACKUP_SEMANTICS屬性才使CreateFile()函數來進行打開文件夾的操作。
通常,文件、文件夾的時間屬性指的是創建時間、最近訪問時間和最近修改時間 等幾個具體屬性。對於文件的上述屬性可以通過GetFileTime()來獲取,對於文件夾,在 通過CreateFile()函數將其打開後,其獲取得到的句柄可以當作文件句柄來使用。因此, 通過GetFileTime()函數同樣也可以得到文件夾的時間屬性。GetFileTime()函數原型如下 :
BOOL GetFileTime( HANDLE hFile, // 文件句柄
LPFILETIME lpCreationTime, // 創建時間的地址
LPFILETIME lpLastAccessTime, // 最近 訪問時間的地址
LPFILETIME lpLastWriteTime // 最近修改時間的地址
);
其中後三個參數均是指向FILETIME結構的指針,得到的也都是UTC時 間,如果需要,可以通過FileTimeToLocalFileTime()函數將此UTC時間轉化成本地時間。 而且還可以進一步通過FileTimeToSystemTime()函數將其從文件時間格式轉化成系統時間 格式,轉化後的時間格式將保存在一個SYSTEMTIME結構對象中。類似的,在將時間信息寫 入到文件夾屬性時,如果不是文件時間格式也應當通過SystemTimeToFileTime()函數將其 從系統時間格式轉換成文件時間格式,然後再通過SetFileTime()函數將指定的時間寫入 到文件夾的時間屬性中去。這樣,在進行數據備份和恢復的過程中,包括根目錄在內的所 有文件夾都可以保持時間屬性的一致。
簡單示例
下面根據前面的講述而給 出一個簡單的應用示例,通過此示例可以從指定的文件夾讀取時間屬性信息並可在經過修 改後再回寫進去(在此僅對最近修改時間進行處理,對於其他的時間屬性可用類似的方法 加以實現)。這裡通過兩個函數GetDirTime()和SetDirTime()來實現對文件夾時間信息的 獲取與更改處理,下面就以注釋的形式對這兩個函數的實現過程進行講解:
// 獲取指定文件夾的時間屬性,入口參數DirName指定了待處理的文件夾,stime為一
// 指向SYSTEMTIME結構的指針
BOOL CSetForderTimeDlg::GetDirTime(CString DirName, SYSTEMTIME &stime){
// 打開文件夾
HANDLE hDir = CreateFile (DirName, GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_DELETE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
FILETIME lpCreationTime; // 文件夾的創建時間
FILETIME lpLastAccessTime; // 對文件 夾的最近訪問時間
FILETIME lpLastWriteTime; // 文件夾的最近修改時間
// 獲取文件夾時間屬性信息
if (GetFileTime(hDir, &lpCreationTime, &lpLastAccessTime, &lpLastWriteTime)){
FILETIME ftime;
FileTimeToLocalFileTime(&lpLastWriteTime, &ftime); // 轉換成本地時間
FileTimeToSystemTime(&ftime, &stime); // 轉換成系統時間格式
}
CloseHandle(hDir); // 關閉打開過的文件夾
return retval;
}
// 設置指定文件夾的時間屬性,入口參數DirName指定了待處理的文件夾, new_time
// 為一指向SYSTEMTIME結構的指針
BOOL CSetForderTimeDlg::SetDirTime(CString DirName, SYSTEMTIME new_stime){
// 打開目錄的Win32 API調用
HANDLE hDir = CreateFile(DirName, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_DELETE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
FILETIME lpCreationTime; // 文件夾的創建時間
FILETIME lpLastAccessTime; // 對文件 夾的最近訪問時間
FILETIME lpLastWriteTime; // 對文件夾的最近修改時間
SystemTimeToFileTime(&new_stime, &lpCreationTime); // 轉換成文件時間 格式
SystemTimeToFileTime(&new_stime, &lpLastAccessTime);
SystemTimeToFileTime(&new_stime, &lpLastWriteTime);
// 設置文件 夾的時間屬性
BOOL retval = SetFileTime(hDir, &lpCreationTime, &lpLastAccessTime, &lpLastWriteTime);
CloseHandle(hDir); // 關閉 文件夾
return retval;
}
至此,可以很方便的通過調用 GetDirTime()和SetDirTime()函數來實現對任意指定文件夾時間屬性的獲取與設置,具體 為:
SYSTEMTIME stime; // 系統時間結構對象
if (GetDirTime (m_Path, stime))
{
// 如果獲取文件夾時間屬性成功,獲取到的時間信息 將保存在stime結構對象中
……
// 如果需要可以對獲取到 的時間屬性進行修改,也可以保留不變
……
// 將修改後 的時間屬性回寫到文件夾
SetDirTime(m_Path, stime);
}
小結
本文通過CreateFile()函數打開文件夾,並在以後的處理中將其以文件來對 待,從而可以使用GetFileTime()、SetFileTime()等函數來對其時間屬性進行獲取與寫入 處理,可對包括根目錄在內的任意文件夾進行時間屬性設置。在數據的完整備份與復原等 方面中有較好的應用前景。本文所述代碼在Windows 2000 Professional下,由Microsoft Visual C++ 6.0編譯通過。