Delete a directory with a non-empty subdirectory and files

How to delete one directory with some files and a non-empty subdirectory.
I tried the SHFileOperation function . He has a compatibility issue in Windows 7 .
Then I tried the IFileOperation Interface . But it is incompatible in Windows XP . Then I tried the following codes suggested by David Heffernan :

procedure TMainForm.BitBtn01Click(Sender: TObject); var FileAndDirectoryExist: TSearchRec; ResourceSavingPath : string; begin ResourceSavingPath := (GetWinDir) + 'Web\Wallpaper\'; if FindFirst(ResourceSavingPath + '\*', faAnyFile, FileAndDirectoryExist) = 0 then try repeat if (FileAndDirectoryExist.Name <> '.') and (FileAndDirectoryExist.Name <> '..') then if (FileAndDirectoryExist.Attr and faDirectory) <> 0 then //it a directory, empty it ClearFolder(ResourceSavingPath +'\' + FileAndDirectoryExist.Name, mask, recursive) else //it a file, delete it DeleteFile(ResourceSavingPath + '\' + FileAndDirectoryExist.Name); until FindNext(FileAndDirectoryExist) <> 0; //now that this directory is empty, we can delete it RemoveDir(ResourceSavingPath); finally FindClose(FileAndDirectoryExist); end; end; 

But it does not compile with mentioning the error as Undeclared Identifier in ClearFolder , mask and recursive . My requirement is that "If any subfolder exists in the WALLPAPER folder, it will be deleted." The same subfolder can contain any number of non-empty subfolders or files.

+4
source share
3 answers

Well, for starters, SHFileOperation has no compatibility issues in Windows 7 or Windows 8. Yes, now you are advised to use IFileOperation . But if you want to support older operating systems such as XP, you can and should just call SHFileOperation . It works and will continue to work. This is great for use on Windows 7 and Windows 8, and I will eat a hat if it ever removes it from Windows. Microsoft has extraordinary lengths to support backward compatibility. So SHFileOperation is your best option in my opinion.

Your FindFirst based approach fails because you need to put it in a separate function to enable recursion. And the code I wrote in this other answer is incomplete. Here is the full version:

 procedure DeleteDirectory(const Name: string); var F: TSearchRec; begin if FindFirst(Name + '\*', faAnyFile, F) = 0 then begin try repeat if (F.Attr and faDirectory <> 0) then begin if (F.Name <> '.') and (F.Name <> '..') then begin DeleteDirectory(Name + '\' + F.Name); end; end else begin DeleteFile(Name + '\' + F.Name); end; until FindNext(F) <> 0; finally FindClose(F); end; RemoveDir(Name); end; end; 

This removes the directory and its contents. You want to go to the top level directory and then call this function for each subdirectory found.

+7
source

Finally, I applied the following code:

 uses ShellAPI; ... ... function GetWinDir: string; var WindowsDirectory: array[0..MAX_PATH] of Char; begin GetWindowsDirectory(WindowsDirectory, MAX_PATH - 1); SetLength(Result, StrLen(WindowsDirectory)); Result := IncludeTrailingPathDelimiter(WindowsDirectory); end; ... ... procedure DeleteDirectory(const DirName: string); var FileFolderOperation: TSHFileOpStruct; begin FillChar(FileFolderOperation, SizeOf(FileFolderOperation), 0); FileFolderOperation.wFunc := FO_DELETE; FileFolderOperation.pFrom := PChar(ExcludeTrailingPathDelimiter(DirName) + #0); FileFolderOperation.fFlags := FOF_SILENT or FOF_NOERRORUI or FOF_NOCONFIRMATION; SHFileOperation(FileFolderOperation); end; ... ... procedure TMainForm.BitBtn01Click(Sender: TObject); begin DeleteDirectory((GetWinDir) + '\Web\Wallpapers\'); end ... ... 

Please do not mention anything about "TrailingPathDelimiter", I intentionally implemented it. I successfully work with one problem that the files or folder were successfully deleted without going to the Recycle Bin in the case of Windows XP, but in the case of Vista and above, these files go to the Recycle Bin, and I don’t have the option to directly delete without sending to " Recycle Bin for Vista or higher.

+2
source

This is a fairly complete function that works with both files and folders. It allows you to specify the following parameters:

  • DeleteToRecycle
  • Showconfirm
  • Totalsilence

{---------------------------------------------- --- --------------
DELETE A FILE
Deletes a file / folder in RecycleBin.
-------------------------------------------------- --------------}

 function RecycleItem(CONST ItemName: string; CONST DeleteToRecycle: Boolean= TRUE; CONST ShowConfirm: Boolean= TRUE; CONST TotalSilence: Boolean= FALSE): Boolean; VAR SHFileOpStruct: TSHFileOpStruct; begin FillChar(SHFileOpStruct, SizeOf(SHFileOpStruct), #0); SHFileOpStruct.wnd := Application.MainForm.Handle; { Others are using 0. But Application.MainForm.Handle is better because otherwise, the 'Are you sure you want to delete' will be hidden under program window } SHFileOpStruct.wFunc := FO_DELETE; SHFileOpStruct.pFrom := PChar(ItemName+ #0); SHFileOpStruct.pTo := NIL; SHFileOpStruct.hNameMappings := NIL; if DeleteToRecycle then SHFileOpStruct.fFlags:= SHFileOpStruct.fFlags OR FOF_ALLOWUNDO; if TotalSilence then SHFileOpStruct.fFlags:= SHFileOpStruct.fFlags OR FOF_NO_UI else if NOT ShowConfirm then SHFileOpStruct.fFlags:= SHFileOpStruct.fFlags OR FOF_NOCONFIRMATION; Result:= SHFileOperation(SHFileOpStruct)= 0; end; 
0
source

All Articles