思路和方法
我們?cè)赪indows環(huán)境下開(kāi)發(fā)某些具有數(shù)據(jù)備份和恢復(fù)等功能的軟件時(shí),需要在拷貝文件及其目錄時(shí)把文件和目錄的所有屬性,包括日期和時(shí)間都能完全地保存并還原出來(lái)。但我們發(fā)現(xiàn),在Windows環(huán)境下沒(méi)有提供任何方法和手段讓我們修改一個(gè)目錄的日期和時(shí)間。在查找Win32 API時(shí)也只能看到修改文件時(shí)間的API函數(shù)調(diào)用,沒(méi)有關(guān)于修改目錄時(shí)間的任何描述。在查看Windows提供的備份程序的功能實(shí)現(xiàn)時(shí),發(fā)現(xiàn)它可以原樣地恢復(fù)所有子目錄的時(shí)間(很遺憾,根目錄的時(shí)間沒(méi)有恢復(fù)),于是我們就從與備份有關(guān)的Win32 API入手,終于找到解決之道:就是以“備份”方式,像打開(kāi)文件那樣打開(kāi)目錄。具體來(lái)說(shuō),就是以FILE—FLAG—BACKUP—SEMANTICS屬性來(lái)調(diào)用CreateFile() Win32 API函數(shù)來(lái)打開(kāi)目錄,然后再調(diào)用和修改文件時(shí)間一樣的SetFileTime() Win32 API函數(shù)來(lái)修改目錄的時(shí)間即可。
這樣,在我們的備份和恢復(fù)程序中,所有目錄(包括根目錄)都可以完全恢復(fù)原來(lái)的日期和時(shí)間了。同樣的技術(shù)也可以用于其它的用途,如可以考慮給Windows的資源管理器增加“修改目錄時(shí)間”的功能等。
具體實(shí)現(xiàn)修改
以下是具體實(shí)現(xiàn)的VC++ 6.0源代碼,它首先將指定目錄(如“C:\dir”)當(dāng)前的時(shí)間顯示出來(lái),然后把它修改成指定時(shí)間,最后把修改后的目錄的時(shí)間顯示出來(lái)。
BOOL SetDirTime(char DirName, SYSTEMTIME new—stime) // 修改指定目錄的時(shí)間
{ HANDLE hDir;
hDir = CreateFile (// 打開(kāi)目錄的Win32 API調(diào)用
DirName,
GENERIC—READ | GENERIC—WRITE,
// 必須“寫(xiě)”方式打開(kāi)
FILE—SHARE—READ|FILE—SHARE—DELETE,NULL,OPEN—EXISTING,
// 打開(kāi)現(xiàn)存的目錄
FILE—FLAG—BACKUP—SEMANTICS,
// 只有這樣才能打開(kāi)目錄
NULL);
if (hDir ==INVALID—HANDLE—VALUE )
return FALSE; // 打開(kāi)失敗時(shí)返回
FILETIME lpCreationTime;
// creation time目錄的創(chuàng)建時(shí)間
FILETIME lpLastAccessTime; // last access time最近一次訪問(wèn)目錄的時(shí)間
FILETIME lpLastWriteTime;// last write time最近一次修改目錄的時(shí)間
SystemTimeToFileTime(&new—stime, &lpCreationTime); // 轉(zhuǎn)換成文件的時(shí)間格式
SystemTimeToFileTime(&new—stime, &lpLastAccessTime);
SystemTimeToFileTime(&new—stime, &lpLastWriteTime);
BOOL retval = SetFileTime( // 修改目錄時(shí)間的Win32 API函數(shù)調(diào)用
hDir, &lpCreationTime,&lpLastAccessTime,&lpLastWriteTime);
CloseHandle(hDir); // 關(guān)閉目錄
return retval;
// 返回修改成功與否的返回碼
}
BOOL GetDirTime(char DirName, SYSTEMTIME & stime) // 獲取指定目錄的時(shí)間
{ HANDLE hDir;
hDir = CreateFile ( // 打開(kāi)目錄的Win32 API調(diào)用
DirName,GENERIC—READ,
// 只需讀方式打開(kāi)即可
FILE—SHARE—READ|FILE—SHARE—DELETE, NULL, OPEN—EXISTING,
// 打開(kāi)現(xiàn)存的目錄
FILE—FLAG—BACKUP—SEMANTICS,NULL);
FILETIME lpCreationTime;
// creation time目錄創(chuàng)建時(shí)間
FILETIME lpLastAccessTime;
// last access time目錄最近訪問(wèn)時(shí)間
FILETIME lpLastWriteTime;
// last write time目錄最近修改時(shí)間
BOOL retval = GetFileTime(
// 獲取目錄日期和時(shí)間的Win32 API調(diào)用
hDir,&lpCreationTime,&lpLastAccessTime &lpLastWriteTime);
if ( retval ){
FILETIME ftime;
FileTimeToLocalFileTime(&lpLastWriteTime, &ftime); // 轉(zhuǎn)換成本地時(shí)間
FileTimeToSystemTime(&ftime, &stime) ; // 轉(zhuǎn)換成系統(tǒng)時(shí)間格式}
CloseHandle(hDir);
return retval;}
int DoTest(char DirName)
{ SYSTEMTIME stime;
printf(″testing for directory [%s]\n″, DirName);
if ( GetDirTime(DirName, stime) )
// 顯示修改前目錄的時(shí)間
printf(″before change is %04d-%02d-%02d %02d:%02d:%02d\n″,
stime.wYear , stime.wMonth , stime.wDay ,
stime.wHour , stime.wMinute, stime.wSecond );
else
printf(″failed to get the datetime of directory...\n″);
stime.wYear = 1995;
stime.wMonth = 5;
stime.wDay = 12;
stime.wHour = 10 - 8; // GMT time, GMT+8 for China PRC
stime.wMinute = 11;
stime.wSecond = 12;
// GetSystemTime(&stime);
// 如果要設(shè)置成當(dāng)前的時(shí)間
if ( SetDirTime(DirName, stime) )
// 修改目錄的時(shí)間
printf(″success to change datetime of directory.\n″);
else
printf(″failed to change the datetime of directory...\n″);
if ( GetDirTime(DirName, stime) )
// 顯示修改后目錄的時(shí)間
printf(″after change is %04d-%02d-%02d %02d:%02d:%02d\n″,stime.wYear , stime.wMonth , stime.wDay ,stime.wHour , stime.wMinute, stime.wSecond );
else
printf(″failed to get the datetime of directory...\n″);
return 0;}
void main(int argc, char argv[])
{ DoTest(″c:\\dir″);}
我們?cè)赪indows環(huán)境下開(kāi)發(fā)某些具有數(shù)據(jù)備份和恢復(fù)等功能的軟件時(shí),需要在拷貝文件及其目錄時(shí)把文件和目錄的所有屬性,包括日期和時(shí)間都能完全地保存并還原出來(lái)。但我們發(fā)現(xiàn),在Windows環(huán)境下沒(méi)有提供任何方法和手段讓我們修改一個(gè)目錄的日期和時(shí)間。在查找Win32 API時(shí)也只能看到修改文件時(shí)間的API函數(shù)調(diào)用,沒(méi)有關(guān)于修改目錄時(shí)間的任何描述。在查看Windows提供的備份程序的功能實(shí)現(xiàn)時(shí),發(fā)現(xiàn)它可以原樣地恢復(fù)所有子目錄的時(shí)間(很遺憾,根目錄的時(shí)間沒(méi)有恢復(fù)),于是我們就從與備份有關(guān)的Win32 API入手,終于找到解決之道:就是以“備份”方式,像打開(kāi)文件那樣打開(kāi)目錄。具體來(lái)說(shuō),就是以FILE—FLAG—BACKUP—SEMANTICS屬性來(lái)調(diào)用CreateFile() Win32 API函數(shù)來(lái)打開(kāi)目錄,然后再調(diào)用和修改文件時(shí)間一樣的SetFileTime() Win32 API函數(shù)來(lái)修改目錄的時(shí)間即可。
這樣,在我們的備份和恢復(fù)程序中,所有目錄(包括根目錄)都可以完全恢復(fù)原來(lái)的日期和時(shí)間了。同樣的技術(shù)也可以用于其它的用途,如可以考慮給Windows的資源管理器增加“修改目錄時(shí)間”的功能等。
具體實(shí)現(xiàn)修改
以下是具體實(shí)現(xiàn)的VC++ 6.0源代碼,它首先將指定目錄(如“C:\dir”)當(dāng)前的時(shí)間顯示出來(lái),然后把它修改成指定時(shí)間,最后把修改后的目錄的時(shí)間顯示出來(lái)。
BOOL SetDirTime(char DirName, SYSTEMTIME new—stime) // 修改指定目錄的時(shí)間
{ HANDLE hDir;
hDir = CreateFile (// 打開(kāi)目錄的Win32 API調(diào)用
DirName,
GENERIC—READ | GENERIC—WRITE,
// 必須“寫(xiě)”方式打開(kāi)
FILE—SHARE—READ|FILE—SHARE—DELETE,NULL,OPEN—EXISTING,
// 打開(kāi)現(xiàn)存的目錄
FILE—FLAG—BACKUP—SEMANTICS,
// 只有這樣才能打開(kāi)目錄
NULL);
if (hDir ==INVALID—HANDLE—VALUE )
return FALSE; // 打開(kāi)失敗時(shí)返回
FILETIME lpCreationTime;
// creation time目錄的創(chuàng)建時(shí)間
FILETIME lpLastAccessTime; // last access time最近一次訪問(wèn)目錄的時(shí)間
FILETIME lpLastWriteTime;// last write time最近一次修改目錄的時(shí)間
SystemTimeToFileTime(&new—stime, &lpCreationTime); // 轉(zhuǎn)換成文件的時(shí)間格式
SystemTimeToFileTime(&new—stime, &lpLastAccessTime);
SystemTimeToFileTime(&new—stime, &lpLastWriteTime);
BOOL retval = SetFileTime( // 修改目錄時(shí)間的Win32 API函數(shù)調(diào)用
hDir, &lpCreationTime,&lpLastAccessTime,&lpLastWriteTime);
CloseHandle(hDir); // 關(guān)閉目錄
return retval;
// 返回修改成功與否的返回碼
}
BOOL GetDirTime(char DirName, SYSTEMTIME & stime) // 獲取指定目錄的時(shí)間
{ HANDLE hDir;
hDir = CreateFile ( // 打開(kāi)目錄的Win32 API調(diào)用
DirName,GENERIC—READ,
// 只需讀方式打開(kāi)即可
FILE—SHARE—READ|FILE—SHARE—DELETE, NULL, OPEN—EXISTING,
// 打開(kāi)現(xiàn)存的目錄
FILE—FLAG—BACKUP—SEMANTICS,NULL);
FILETIME lpCreationTime;
// creation time目錄創(chuàng)建時(shí)間
FILETIME lpLastAccessTime;
// last access time目錄最近訪問(wèn)時(shí)間
FILETIME lpLastWriteTime;
// last write time目錄最近修改時(shí)間
BOOL retval = GetFileTime(
// 獲取目錄日期和時(shí)間的Win32 API調(diào)用
hDir,&lpCreationTime,&lpLastAccessTime &lpLastWriteTime);
if ( retval ){
FILETIME ftime;
FileTimeToLocalFileTime(&lpLastWriteTime, &ftime); // 轉(zhuǎn)換成本地時(shí)間
FileTimeToSystemTime(&ftime, &stime) ; // 轉(zhuǎn)換成系統(tǒng)時(shí)間格式}
CloseHandle(hDir);
return retval;}
int DoTest(char DirName)
{ SYSTEMTIME stime;
printf(″testing for directory [%s]\n″, DirName);
if ( GetDirTime(DirName, stime) )
// 顯示修改前目錄的時(shí)間
printf(″before change is %04d-%02d-%02d %02d:%02d:%02d\n″,
stime.wYear , stime.wMonth , stime.wDay ,
stime.wHour , stime.wMinute, stime.wSecond );
else
printf(″failed to get the datetime of directory...\n″);
stime.wYear = 1995;
stime.wMonth = 5;
stime.wDay = 12;
stime.wHour = 10 - 8; // GMT time, GMT+8 for China PRC
stime.wMinute = 11;
stime.wSecond = 12;
// GetSystemTime(&stime);
// 如果要設(shè)置成當(dāng)前的時(shí)間
if ( SetDirTime(DirName, stime) )
// 修改目錄的時(shí)間
printf(″success to change datetime of directory.\n″);
else
printf(″failed to change the datetime of directory...\n″);
if ( GetDirTime(DirName, stime) )
// 顯示修改后目錄的時(shí)間
printf(″after change is %04d-%02d-%02d %02d:%02d:%02d\n″,stime.wYear , stime.wMonth , stime.wDay ,stime.wHour , stime.wMinute, stime.wSecond );
else
printf(″failed to get the datetime of directory...\n″);
return 0;}
void main(int argc, char argv[])
{ DoTest(″c:\\dir″);}