【问题标题】:Can't delete folder from a different partition无法从其他分区删除文件夹
【发布时间】:2014-07-31 12:20:23
【问题描述】:

从我的软件中删除位于不同分区 (E:/) 上的文件夹时遇到问题。我可以使用 DeleteFile 函数删除文件,但我无法使用以下代码删除文件夹:

function RemoveDirectory(strDir : String) : Boolean;
var
  SearchRec : TSearchRec;
  strFile   : String;
  nResult   : Integer;
begin
  try
    Result := false;

    nResult := FindFirst(strDir + '*', faAnyFile, SearchRec);

    while (nResult = 0) do
      begin
        if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then
          begin
            strFile := strDir +  SearchRec.Name;

            if FileExists(strFile) then
              DeleteFile(strFile)
            else if DirectoryExists(strFile) then
              RemoveDirectory(strFile);
          end;
        nResult := FindNext(SearchRec);
      end;

    Result := RemoveDir(strDir);
  finally
    FindClose(SearchRec);
  end;
end;

使用此代码,我可以从我的软件中删除位于同一分区上的文件夹。有人知道发生了什么吗?是不是因为它在不同的分区上?

【问题讨论】:

  • 在调试器中单步执行代码时会发生什么?您是否检查任何错误/返回值或引发任何异常?这些都将帮助您解决问题。
  • 文件是否在同一个映射驱动器上并不重要。有些东西阻止你删除文件/目录。您没有检查错误的事实是一个令人担忧的迹象。如果你想知道哪里出了问题,为什么你忽略了检查错误?为什么要使用FileExistsDirectoryExistsSearchRec.Attr 告诉你这些信息。你的try/finally 也全错了。 try 太快了。下一步是添加错误检查。
  • 可以手动删除这些目录吗?
  • 好的,我添加了错误检查并得到错误32,这表明某些进程正在使用它。但是如果我在这个函数之前放一个睡眠,然后我自己去,我可以手动删除文件夹。所以我认为保存文件夹的是函数本身。 PS:该目录内的所有文件(里面没有文件夹)都被成功删除了。
  • 我注意到您在 FindClose(SearchRec); 之前致电 Result := RemoveDir(strDir)。我不会肯定地说这是你的问题,(你应该注意有关错误处理的警告)但它仍然让我觉得从后到前。

标签: delphi delphi-6


【解决方案1】:

您正在尝试删除目录,而您仍然有打开的搜索句柄。由于这是一个递归函数,如果目录层次结构较深,您将同时打开多个搜索句柄,当到达较深的文件夹时会占用大量系统资源。

最好将直接子文件夹收集到一个临时列表中,然后您可以在迭代该列表之前关闭当前搜索句柄。这样,一次只有一个搜索句柄处于活动状态,并且在每个文件夹实际被删除时没有搜索句柄处于活动状态。

试试这个:

function RemoveDirectory(strDir : String) : Boolean;
var
  SearchRec : TSearchRec;
  nResult,i : Integer;
  SubFolders: TStringList;
begin
  SubFolders := nil;
  try
    strDir := IncludeTrailingPathDelimiter(strDir);

    nResult := FindFirst(strDir + '*', faAnyFile, SearchRec);
    if (nResult = 0) then
    try
      repeat
        if (SearchRec.Attr and faDirectory) = 0 then
          DeleteFile(strDir + SearchRec.Name)
        else
        begin
          if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then
          begin
            if not Assigned(SubFolders) then SubFolders := TStringList.Create;
            SubFolders.Add(strDir + SearchRec.Name);
          end;
        end;
      until FindNext(SearchRec) <> 0;
    finally
      FindClose(SearchRec);
    end;

    if Assigned(SubFolders) then
    begin
      for i := 0 to SubFolders.Count-1 do
        RemoveDirectory(SubFolders[i]);
    end;
  finally
    SubFolders.Free;
  end;

  Result := RemoveDir(strDir);
end;

如果这仍然失败,那么您的应用程序/循环之外的其他人实际上正在使用这些目录,您可以使用像 SysInternals Process Explorer 这样的工具来检查。

【讨论】:

  • 能否解释一下为什么原来的代码会失败,为什么这段代码不会失败?
  • 我看不出您需要字符串列表。另外,如果目录是打开的搜索记录,您确定不能删除目录吗?
  • 使用 StringList 的主要目的是不要同时打开多个搜索句柄。由于这是一个递归函数,如果目录层次结构很深,那么在到达更深的文件夹时就会使用大量系统资源。这就是为什么最好将直接子文件夹收集到临时列表中,关闭当前搜索句柄,然后迭代子文件夹。这样,一次只有 1 个搜索句柄处于活动状态,并且在实际删除每个文件夹时没有搜索句柄处于活动状态。
  • 这是有道理的。我希望该信息在答案中。我怀疑你是对的,打开搜索句柄可能是一个问题。尽管似乎并非总是如此。
  • @Remy - 在关闭搜索句柄之前删除文件夹肯定有问题吗?我不确定。
【解决方案2】:

DeleteFile() 是一个布尔函数,你只能接收到它成功与否的信息。如果您想了解更多详细信息,请返回普通的 Erase():

var f: file;

begin
  AssignFile(f,strFile);
  Erase(f);
end;

这里,如果 Erase() 没有完成,则会引发异常,您可以收到更多信息,尤其是在调试阶段。

【讨论】:

  • -1 Windows DeleteFile API 是在 Delphi 6 中删除文件的正确方法。SysUtils 中的同名函数仅通过调用 Win32 API 来实现功能。如果函数返回 false,那么您调用 GetLastError 以了解更多信息。这在文档中有详细的说明:msdn.microsoft.com/en-gb/library/windows/desktop/aa363915.aspx 调用RaiseLastOSErrorWin32Check 结束。
  • 当然,Erase 是在操作系统之上实现的。因此,它只不过是调用 Win32 DeleteFile,然后调用 GetLastError 以防失败。推荐传统的 Pascal I/O 不是前进的方向。
  • 修改遗留代码,现在多平台。这是当今找出无法在 Mac 或 Android 上删除文件的正确方法。
  • 当然不是。 x-plat 文件处理实用程序位于 IOUtils 单元中。
  • 你为什么不直接测试一下呢?对于 windows 和 fox osx,它工作得很好。
猜你喜欢
  • 2021-01-24
  • 2020-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多