【问题标题】:Recursively delete files and skip files that are in use?递归删除文件并跳过正在使用的文件?
【发布时间】:2014-05-12 13:36:04
【问题描述】:

我正在使用 Windows API 递归删除许多文件和文件夹。我在没有 UI 的情况下使用它并抑制错误。问题是,如果其中一个文件正在使用中,它会完全失败。我期待这种可能性,并希望这种情况继续下去,跳过任何此类情况。失败的文件实际上是调用此删除命令的同一个 EXE(无论如何都会在全部完成后删除。

这是我现在正在做的事情:

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;

我怎样才能让它跳过正在使用的文件的任何事件?我查看了the documentation,但找不到任何可以做到这一点的东西。

【问题讨论】:

  • IFileOperation 可以处理这个问题。您可能需要使用它,或者使用递归 FindFirst、FindNext 方法自行遍历目录。
  • 您应该发布显示问题的代码......而不是有效的代码!
  • @JochenKalmbach 你看我的问题了吗?
  • @Jerry 我的答案中的第二个代码示例将满足您的需求:stackoverflow.com/questions/11798783/…
  • 我认为是 IFileOperation 或手动树行走

标签: delphi winapi shfileoperation


【解决方案1】:

这只是一个想法,您可以在函数中实现以验证是否有任何文件正在使用:

function IsFileInUse(FileName: TFileName): Boolean;
var
  HFileRes: HFILE;
begin
  Result := False;
  if not FileExists(FileName) then
    Exit;

  HFileRes := CreateFile(PChar(FileName),
                         GENERIC_READ or GENERIC_WRITE,
                         0,
                         nil,
                         OPEN_EXISTING,
                         FILE_ATTRIBUTE_NORMAL,
                         0);
  Result := (HFileRes = INVALID_HANDLE_VALUE);

  if not Result then
    CloseHandle(HFileRes);
end;

也许它可以帮助你。

【讨论】:

  • 这将如何与对SHFileOperation 的调用交互?
  • 我以不同的方式使用它。我在目录中的所有文件中使用循环,然后在删除它之前检查当前文件是否正在使用。正如我所说,这只是一个想法。
  • 在这种情况下,您只需调用 DeleteFile 并忽略返回值。如果文件无法删除,则不会删除,DeleteFile 将返回 true。像这样尝试第二次猜测是毫无意义的。
  • 是的,调用DeleteFile 是正确的方法。调用CreateFile 也会修改最后一次访问时间,这不是有意的……而且即使CreateFile 成功了,在DeleteFile 中也可能会失败……
  • 否 -1 但这并不能解决我正在做的事情。最后,没有必要进行此检查,因为 Windows 无论如何都会自动失败。问题是,使用我的方法,我无法弄清楚如何让它继续自动删除其他所有内容并跳过正在使用的所有内容。
【解决方案2】:

你为什么不试试这个:

procedure DeleteFiles(const DirName: String);
var
  SR: TSearchRec;
  i: Integer;
begin
  //get all files in directory
  i := FindFirst(DirName +'\*.*', faAnyFile, SR);

  while i = 0 do
  begin
    if (SR.Attr and faDirectory) <> faDirectory then
      DeleteFile(DirName +'\'+ SR.Name);

    i := FindNext(SR);
  end;

  FindClose(SR);
end;

这是另一种方式。

【讨论】:

  • 因为它不是递归的。
  • *.* 的存在真是太棒了。只需* 就足够了。
猜你喜欢
  • 1970-01-01
  • 2020-02-18
  • 2022-07-26
  • 2012-09-04
  • 1970-01-01
  • 2011-01-02
  • 2014-06-21
  • 2012-11-19
  • 1970-01-01
相关资源
最近更新 更多