如何在Delphi中正确使用IFileOperation删除文件夹中的文件 [英] How to correctly use IFileOperation in Delphi to delete the files in a folder

查看:158
本文介绍了如何在Delphi中正确使用IFileOperation删除文件夹中的文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to create a simple example of using IFileOperation to delete the files in a given directory, to include in the answer to another q for comparison with other methods.

下面是我的 MRE 的代码。
成功在C:\Temp的子目录中创建了1000个文件,然后尝试通过 DeleteFiles 方法删除
。这个简单的任务失败了,但我不确定
到底在哪里。代码中的注释显示了我期望的
和实际结果。有一次,我没有弹出一个例外,而是弹出一个
,要求确认删除一个带有奇数名称的项目,这显然是一个数组
的数字,表示一个外壳项目,但是尝试使用Ctrl-C捕获它失败;

Below is the code of my MRE. It successfully creates 1000 files in a subdirectory off C:\Temp and then attempts to delete them in the DeleteFiles method. This supposedly "easy" task fails but I'm not sure exactly where it comes off the rails. The comments in the code show what I'm expecting and the actual results. On one occasion, instead of the exception noted, I got a pop-up asking for confirmation to delete an item with an odd name which was evidently an array of numbers referring to a shell item, but my attempt to capture it using Ctrl-C failed;

我相当确定我错过了一两个步骤,或者误用了涉及到
的界面。我的问是,有人可以对代码进行必要的更正以获取IFileOperation.DeleteItems()来删除有问题的文件,因为我完全不了解这些东西吗?我对使用shell界面或其他方式删除这些文件的替代方法不感兴趣。

I'm fairly sure I'm either missing a step or two, misusing the interfaces involved or both. My q is, could anybody please show the necessary corrections to the code to get IFileOperation.DeleteItems() to delete the files in question, as I am completely out of my depth with this stuff? I am not interested in alternative methods of deleting these files, using the shell interfaces or otherwise.

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;


推荐答案

您正在泄漏<$ c $返回的内存c> ILCreateFromPath(),使用返回的 PItemIDList ILFree() c $ c>。

You are leaking the memory returned by ILCreateFromPath(), you need to call ILFree() when you are done using the returned PItemIDList.

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

Also, you should not be dereferencing the PItemIDList. SHCreateShellItemArrayFromIDLists() expects an array of PItemIDList pointers, but you are giving it an array of ItemIDList instances.

尝试以下操作:

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;

话虽如此,即使此方法工作正常,也不会创建 IShellItemArray ,其中每个文件包含1000个 IShellItem 。您正在为 C:ItemTemp IShellItemArray ,其中包含1个 IShellItem 。 c $ c>子目录本身。

That being said, even if this were working correctly, you are not creating an IShellItemArray containing 1000 IShellItems for the individual files. You are creating an IShellItemArray containing 1 IShellItem for the C:\Temp subdirectory itself.

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

Which is fine if your goal is to delete the whole folder. But in that case, I would suggest using SHCreateItemFromIDList() or SHCreateItemFromParsingName() instead, and then pass that IShellItem to IFileOperation.DeleteItem().

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

But, if your goal is to delete the individual files without deleting the subdirectory as well, then you will have to either:


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

  • get the IShellFolder interface for the subdirectory, then enumerate the relative PIDLs of its files using IShellFolder.EnumObjects(), and then pass the PIDLs in an array to SHCreateShellItemArray().

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

get the IShellFolder interface of the subdirectory, then query it for an IDataObject interface using IShellFolder.GetUIObjectOf(), and then use SHCreateShellItemArrayFromDataObject(), or just give the IDataObject directly to IFileOperation.DeleteItems().

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

get an IShellItem interface for the subdirectory, then query its IEnumShellItems interface using IShellItem.BindToHandler(), and then pass that directly to IFileOperation.DeleteItems().

这篇关于如何在Delphi中正确使用IFileOperation删除文件夹中的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆