繁体   English   中英

如何正确使用Delphi中的IFileOperation删除文件夹中的文件

[英]How to correctly use IFileOperation in Delphi to delete the files in a folder

我正在尝试创建一个使用 IFileOperation 删除给定目录中的文件的简单示例,以包含在另一个 q 的答案中,以便与其他方法进行比较。

下面是我的MRE的代码。 它成功地在 C:\Temp 的子目录中创建了 1000 个文件,然后尝试在DeleteFiles方法中删除它们。 这个所谓的“简单”任务失败了,但我不确定它到底是从哪里脱轨的。 代码中的注释显示了我的期望和实际结果。 有一次,我没有注意到异常,而是弹出一个要求确认删除具有奇怪名称的项目的弹出窗口,这显然是一个引用 shell 项目的数字数组,但我尝试使用 Ctrl-C 捕获它失败的;

我很确定我要么缺少一两个步骤,要么滥用所涉及的接口,要么两者兼而有之。 我的问题是,任何人都可以对代码进行必要的更正以让 IFileOperation.DeleteItems() 删除有问题的文件,因为我对这些东西完全不了解吗? 我对使用 shell 接口或其他方式删除这些文件的替代方法不感兴趣。

procedure TForm2.DeleteFiles;
var
  iFileOp: IFileOperation;
  iIDList : ItemIDList;
  iItemArray : IShellItemArray;
  iArray : Array[0..1] of ItemIDList;
  Count : DWord;
begin
  iFileOp := CreateComObject(CLSID_FileOperation) as IFileOperation;

  iIDList := ILCreateFromPath(sPath)^;

  //  IFileOperation.DeleteItems seems to require am IShellItemArray, so the following attempts
  //  to create one
  //  The definition of SHCreateShellItemArrayFromIDLists
  //  seems to require a a zero-terminated array of ItemIDLists so the next steps
  //  attempt to create one

  ZeroMemory(@iArray, SizeOf(iArray));
  iArray[0] := iIDList;
  OleCheck(SHCreateShellItemArrayFromIDLists(1, @iArray, iItemArray));

  //  Next test the number of items in iItemArray, which I'm expecting to be 1000
  //  seeing as the CreateFiles routine creats that many

  OleCheck(iItemArray.GetCount(Count));
  Caption := IntToStr(Count);  //  Duh, this shows Count to be 1, not the expected 1000

  OleCheck(iFileOp.DeleteItems(iItemArray));
  OleCheck( iFileOp.PerformOperations );
  // Returns Exception 'No object for moniker'

end;

procedure TForm2.Button1Click(Sender: TObject);
begin
  DeleteFiles;
end;

procedure CreateFiles;
var
  i : Integer;
  SL : TStringList;
  FileName,
  FileContent : String;
begin

  SL := TStringList.Create;
  try
    if not (DirectoryExists(sPath)) then
      MkDir(sPath);

    SL.BeginUpdate;
    for i := 0 to 999 do begin
      FileName := Format('File%d.Txt', [i]);
      FileContent := Format('content of file %s', [FileName]);
      SL.Text := FileContent;
      SL.SaveToFile(sPath + '\' + FileName);
    end;
    SL.EndUpdate;
  finally
    SL.Free;
  end;
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  CreateFiles;
end;

您正在泄漏ILCreateFromPath()返回的 memory ,您需要在使用返回的PItemIDList完成后调用ILFree()

此外,您不应该取消引用PItemIDList SHCreateShellItemArrayFromIDLists()需要一个PItemIDList指针数组,但您给它的是一个ItemIDList实例数组。

试试这个:

procedure TForm2.DeleteFiles;
var
  iFileOp: IFileOperation;
  iIDList : PItemIDList;
  iItemArray : IShellItemArray;
  Count : DWord;
begin
  iFileOp := CreateComObject(CLSID_FileOperation) as IFileOperation;

  iIDList := ILCreateFromPath(sPath);
  try
    OleCheck(SHCreateShellItemArrayFromIDLists(1, @iIDList, iItemArray));
  finally
    ILFree(iIDList);
  end;

  //  Next test the number of items in iItemArray, which I'm expecting to be 1000
  //  seeing as the CreateFiles routine creates that many

  OleCheck(iItemArray.GetCount(Count));
  Caption := IntToStr(Count);  //  Duh, this shows Count to be 1, not the expected 1000

  OleCheck(iFileOp.DeleteItems(iItemArray));
  OleCheck( iFileOp.PerformOperations );
  // Returns Exception 'No object for moniker'
end;

话虽如此,即使这工作正常,您也不会为各个文件创建包含 1000 个IShellItemArrayIShellItem 您正在为IShellItem C:\Temp子目录本身创建一个包含 1 个IShellItemArray的 IShellItemArray。

如果您的目标是删除整个文件夹,这很好。 但在这种情况下,我建议改用SHCreateItemFromIDList()SHCreateItemFromParsingName() ,然后将该IShellItem传递给IFileOperation.DeleteItem()

但是,如果您的目标是删除单个文件而不删除子目录,那么您将不得不:

  • 获取子目录的IShellFolder接口,然后使用IShellFolder.EnumObjects()枚举其文件的相关 PIDL,然后将数组中的 PIDL 传递给SHCreateShellItemArray()

  • 获取子目录的IShellFolder接口,然后使用IShellFolder.GetUIObjectOf()查询IDataObject接口,然后使用SHCreateShellItemArrayFromDataObject() ,或者直接将IDataObject提供给IFileOperation.DeleteItems()

  • 获取子目录的IShellItem接口,然后使用IShellItem.BindToHandler()查询其IEnumShellItems接口,然后将其直接传递给IFileOperation.DeleteItems()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM