使用Delphi递归删除所有文件和文件夹

14

我正在尝试递归删除一个文件夹及其所有子文件夹,但它根本不起作用。请问有谁可以检查一下我的代码并告诉我在这里做错了什么吗?

我正在Windows XP下通过D7运行此代码。

if FindFirst (FolderPath + '\*', faAnyFile, f) = 0 then
      try             
         repeat

            if (f.Attr and faDirectory) <> 0 then
              begin
                    if (f.Name <> '.') and (f.Name <> '..') then
                      begin                            
                        RemoveDir(FolderPath +'\'+ f.Name);
                      end
                    else
                      begin
                        //Call function recursively...
                        ClearFolder(FolderPath +'\'+ f.Name, mask, recursive);
                      end;
              end;

         until (FindNext (f) <> 0);
      finally
        SysUtils.FindClose (f)
      end;
end;

1
使用JclFileUtils中的DeleteDirectory怎么样? - Stefan Glienke
1
你甚至没有发布足够的代码,让任何人有机会真正调试它。我的意思是,我们怎么知道ClearFolder做了什么?从技术上讲,下面的答案都在做出假设,因为你让人们猜测。尽管如此,你的问题很好,而且不是重复的。不错。其他类似的问题都太具体了,而你的标题更加通用。不错。+1给你! - Warren P
1
@Warren,问题中的代码是ClearFolder函数的主体。标准递归。 - David Heffernan
@WarrenP 感谢您抽出时间阅读我的问题,DavidHeffernan 帮助了我并解决了这个问题。 - MChan
可能是重复的问题 Delphi中删除带内容的文件夹 - Vadzim
3个回答

32

与其自己进行这些繁琐的工作,我建议使用SHFileOperation

uses
  ShellAPI;

procedure DeleteDirectory(const DirName: string);
var
  FileOp: TSHFileOpStruct;
begin
  FillChar(FileOp, SizeOf(FileOp), 0);
  FileOp.wFunc := FO_DELETE;
  FileOp.pFrom := PChar(DirName+#0);//double zero-terminated
  FileOp.fFlags := FOF_SILENT or FOF_NOERRORUI or FOF_NOCONFIRMATION;
  SHFileOperation(FileOp);
end;

值得一提的是,你代码的问题在于它从未调用DeleteFile函数。因此目录从未被清空,RemoveDir函数的调用失败等等。你的代码中缺少错误检查并没有太大帮助,但添加删除文件的代码可以使代码达到半可接受的状态。此外,你还需要小心递归操作。你必须确保先删除所有子元素,然后再删除父容器。这需要一定的技巧才能正确地完成。基本的做法如下:

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;

为了清晰起见,我省略了错误检查,但您应该检查DeleteFileRemoveDir的返回值。


明白了!我的代码里有个愚蠢的错误。RemoveDir那行写错了。请看更新。 - David Heffernan
是的,我现在修好了。就像我说的,这需要一定的技巧才能做到,而我用了两次才展示出那种技巧! - David Heffernan
我正在尝试调试,不想只是回来报告它没有工作,所以我想看看可能的原因是什么,但是像我之前评论中提到的那样,我找不到任何原因。 - MChan
David,我认为最好使用PathDelim常量而不是''字面值。 - jachguate
2
@jachguate:由于上述代码非常适用于Win32 API,因此略有些本地化。 - Andreas Rejbrand
显示剩余12条评论

7
procedure DeleteDir(const DirName: string);
var
  Path: string;
  F: TSearchRec;

begin
  Path:= DirName + '\*.*';
  if FindFirst(Path, faAnyFile, F) = 0 then begin
    try
      repeat
        if (F.Attr and faDirectory <> 0) then begin
          if (F.Name <> '.') and (F.Name <> '..') then begin
            DeleteDir(DirName + '\' + F.Name);
          end;
        end
        else
          DeleteFile(DirName + '\' + F.Name);
      until FindNext(F) <> 0;
    finally
      FindClose(F);
    end;
  end;
  RemoveDir(DirName);
end;

这与我的答案中的代码有何不同之处?我能看到的主要区别是RemoveDir在if FindFirst之外,但这并不能产生任何差异。那么为什么你会提供一个基本上与我的答案中完全相同的代码答案呢?而且甚至没有解释它是关于什么的?我很困惑。 - David Heffernan
3
@DavidHeffernan - 这是一个社区网站,每个人都可以自由地提问和回答问题。我并没有真正看到你的最新更新,只是编写并测试了我的代码。 - kludg
1
好的,我明白了,只是看起来有点奇怪,因为代码基本上与我的相同,并且出现在一段时间之后。 - David Heffernan
1
@DavidHeffernan - 如果你是认真的话,我对SO的改写不感兴趣,只是在SO上花一点时间,有时发布一些可能对提问者有帮助的简短答案。 - kludg
3
我想,提供两个相同且经过测试的答案可以向提问者展示代码是有效的。 - David Heffernan

1
从Delphi 2010开始,System.IOUtils单元中有一个TDirectory记录,其中包括一些方法。
TDirectory.Delete('path_to_dir', True);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接