You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Delphi 11.1 VCL应用使用FindFirst/FindNext遍历USB连接安卓手机文件失败求助

Delphi 11.1 VCL应用使用FindFirst/FindNext遍历USB连接安卓手机文件失败求助

嘿,我太懂你这个困境了!Windows资源管理器里明明能看到手机的SD卡路径,直接套FindFirst/FindNext却一直报路径找不到,核心原因是你用的不是传统文件系统路径,而是Windows Shell命名空间里的虚拟路径——这类路径是给资源管理器用的,Delphi的FindFirst这类底层文件函数根本识别不了。

给你几个可行的解决方案:

方案一:把手机存储映射成驱动器号(最简单快捷)

大部分安卓手机用USB连接时是MTP模式,没法直接像U盘那样被识别成磁盘盘符,但你可以用第三方工具(比如MTPDrive、USB Drive for Android)把手机的SD卡/内部存储映射成电脑上的一个驱动器(比如F:、G:)。

映射完成后,你就能用熟悉的文件路径(比如F:\DCIM\Camera\*.jpg)调用FindFirst/FindNext了,代码完全不用大改,直接替换路径就行。

方案二:用Windows Shell API遍历虚拟路径

如果不想依赖第三方工具,就得用Windows的Shell COM接口来访问Shell命名空间里的手机文件。Delphi自带ShellAPIShlObj单元可以实现这个功能,给你一个简单的示例代码:

uses 
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ShellAPI, ShlObj, ActiveX, ComObj;

procedure EnumPhoneShellItems(const ShellNamespacePath: string);
var
  DesktopShellFolder: IShellFolder;
  ItemPIDL: PItemIDList;
  AttrFlags: DWORD;
  ItemEnumerator: IEnumIDList;
  CurrentItemID: PItemIDList;
  DisplayName: array[0..MAX_PATH] of Char;
begin
  // 初始化COM环境(记得在程序启动时调用CoInitialize(nil),退出时CoUninitialize)
  if not Succeeded(SHGetDesktopFolder(DesktopShellFolder)) then Exit;

  // 将Shell路径解析为PIDL(Shell命名空间的唯一标识)
  if not Succeeded(DesktopShellFolder.ParseDisplayName(0, nil, 
    PWideChar(WideString(ShellNamespacePath)), AttrFlags, ItemPIDL, nil)) then Exit;
  try
    // 获取当前路径下的项目枚举器
    if not Succeeded(DesktopShellFolder.BindToObject(ItemPIDL, nil, 
      IID_IEnumIDList, Pointer(ItemEnumerator))) then Exit;

    // 遍历所有项目
    while ItemEnumerator.Next(1, CurrentItemID, nil) = S_OK do
    begin
      // 获取项目的显示名称
      if DesktopShellFolder.GetDisplayNameOf(CurrentItemID, 
        SHGDN_NORMAL or SHGDN_FORPARSING, DisplayName) = S_OK then
      begin
        ShowMessage(StrPas(DisplayName));
        // 这里可以扩展逻辑:判断是文件还是文件夹,递归遍历子目录等
      end;
      CoTaskMemFree(CurrentItemID); // 释放PIDL内存
    end;
  finally
    CoTaskMemFree(ItemPIDL); // 释放根路径PIDL内存
  end;
end;

// 调用示例(替换成你的手机路径)
procedure TForm1.Button1Click(Sender: TObject);
begin
  EnumPhoneShellItems('This PC\My Phone Name\SD card\DCIM\Camera');
end;

注意事项:

  • 必须在程序启动时调用CoInitialize(nil)(比如在FormCreate里),退出时调用CoUninitialize(),否则COM接口会无法正常工作。
  • 这个方法可以直接遍历Shell虚拟路径,但逻辑比传统文件遍历复杂,需要处理PIDL内存释放、文件夹递归等细节。

额外提醒

安卓手机通过USB连接的MTP协议本身就不是为传统文件系统访问设计的,所以别再纠结用FindFirst直接访问This PC开头的路径了——那根本不是它能处理的路径类型。

备注:内容来源于stack exchange,提问作者gorepj01

火山引擎 最新活动