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自带ShellAPI和ShlObj单元可以实现这个功能,给你一个简单的示例代码:
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




