在 Delphi 開發中,雖然 VCL 提供了 CreateDir、RemoveDir 等基本目錄操作函數,但它們僅能處理空目錄。一旦目錄包含子目錄或文件,這些函數便無能為力。本文將介紹如何利用 Win32 API 結合遞歸算法,實現功能相當於 DOS XCopy、DelTree 和 Move 命令的目錄深度拷貝、刪除與移動操作。
拷貝非空目錄的關鍵在於遞歸遍歷源目錄下的所有文件與子目錄,並在目標路徑重建相同的結構。我們將核心邏輯封裝在輔助函數 DoCopyDir 中,主函數 CopyDir 負責參數校驗與調用。
該函數使用 FindFirstFile/FindNextFile 遍歷文件,遇到子目錄則遞歸調用自身,遇到文件則直接調用 CopyFile。注意保存並恢復當前工作目錄,避免遞歸過程中路徑混亂。
function DoCopyDir(sDirName: String; sToDirName: String): Boolean;
var
hFindFile: Cardinal;
t, tfile: String;
sCurDir: String[255];
FindFileData: WIN32_FIND_DATA;
begin
// 保存當前目錄
sCurDir := GetCurrentDir;
ChDir(sDirName);
hFindFile := FindFirstFile('*.*', FindFileData);
if hFindFile <> INVALID_HANDLE_VALUE then
begin
// 確保目標目錄存在
if not DirectoryExists(sToDirName) then
ForceDirectories(sToDirName);
repeat
tfile := FindFileData.cFileName;
// 跳過 "." 和 ".."
if (tfile = '.') or (tfile = '..') then Continue;
if (FindFileData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = FILE_ATTRIBUTE_DIRECTORY then
begin
// 處理子目錄:遞歸調用
t := sToDirName + '\' + tfile;
if not DirectoryExists(t) then ForceDirectories(t);
if sDirName[Length(sDirName)] <> '\' then
DoCopyDir(sDirName + '\' + tfile, t)
else
DoCopyDir(sDirName + tfile, sToDirName + '\' + tfile);
end
else
begin
// 處理文件:直接拷貝
t := sToDirName + '\' + tfile;
CopyFile(PChar(tfile), PChar(t), True); // True 表示不覆蓋已存在文件
end;
until FindNextFile(hFindFile, FindFileData) = False;
FindClose(hFindFile);
end
else
begin
ChDir(sCurDir);
Result := False;
Exit;
end;
// 恢復原始目錄
ChDir(sCurDir);
Result := True;
end;
function CopyDir(sDirName: String; sToDirName: String): Boolean;
begin
if Length(sDirName) <= 0 then Exit;
Result := DoCopyDir(sDirName, sToDirName);
end;
刪除邏輯與拷貝類似,但需特別處理「空目錄」的刪除。引入標志變量 bEmptyDir 追蹤當前遍歷目錄是否為空,遍歷結束後若為空則刪除該目錄本身。
function DoRemoveDir(sDirName: String): Boolean;
var
hFindFile: Cardinal;
tfile: String;
sCurDir: String;
bEmptyDir: Boolean;
FindFileData: WIN32_FIND_DATA;
begin
bEmptyDir := True; // 預設為空目錄
sCurDir := GetCurrentDir;
ChDir(sDirName);
hFindFile := FindFirstFile('*.*', FindFileData);
if hFindFile <> INVALID_HANDLE_VALUE then
begin
repeat
tfile := FindFileData.cFileName;
if (tfile = '.') or (tfile = '..') then
begin
bEmptyDir := bEmptyDir and True;
Continue;
end;
// 發現文件或子目錄,標記為非空
bEmptyDir := False;
if (FindFileData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = FILE_ATTRIBUTE_DIRECTORY then
begin
// 遞歸刪除子目錄
if sDirName[Length(sDirName)] <> '\' then
DoRemoveDir(sDirName + '\' + tfile)
else
DoRemoveDir(sDirName + tfile);
Result := RemoveDirectory(PChar(tfile));
end
else
begin
// 刪除文件
Result := DeleteFile(PChar(tfile));
end;
if not Result then Exit; // 遇到失敗即刻退出
until FindNextFile(hFindFile, FindFileData) = False;
FindClose(hFindFile);
end
else
begin
ChDir(sCurDir);
Result := False;
Exit;
end;
// 若為空目錄,返回上級並刪除自身
if bEmptyDir then
begin
ChDir('..');
RemoveDirectory(PChar(sDirName));
end;
ChDir(sCurDir);
Result := True;
end;
function DeleteDir(sDirName: String): Boolean;
begin
if Length(sDirName) <= 0 then Exit;
Result := DoRemoveDir(sDirName) and RemoveDir(sDirName); // 最後嘗試刪除根目錄本身
end;
有了拷貝與刪除,移動操作便極為簡單:先拷貝到目標位置,成功後刪除源目錄。
function MoveDir(sDirName: String; sToDirName: String): Boolean;
begin
Result := False;
if CopyDir(sDirName, sToDirName) then
if DeleteDir(sDirName) then // 使用封裝好的 DeleteDir
Result := True;
end;
本文提供的代碼展示了 Delphi 中通過 Win32 API 實現目錄樹操作的經典模式。核心要點在於:正確管理工作目錄上下文、妥善處理 . 與 .. 特殊目錄、以及利用遞歸實現樹狀結構的深度遍歷。這些函數可直接集成到項目中,滿足大多數文件管理需求。