Android设备加载共享网络驱动器图片报错求助
问题分析与解决方案
问题重现
我搭建了一个网络驱动器,目录下存有多张.jpg格式图片,希望将这些图片加载到TImage组件中,图片名称从数据库字段读取。实现代码如下:
procedure TForm1.ShowPicture; var fn: string; begin BitMapPath := '\\DRIVE-ABC\Pictures\'; qryPictures.Open; qryPictures.First; if not(qryPictures.FindField('Picture').IsNull) then begin fn := BitMapPath + qryPictures.FieldByName('Picture').AsString; TDialogService.ShowMessage(fn); imgPart.Bitmap.LoadFromFile(fn); end; end;
- Windows x32版本运行正常,能正确读取图片。
- Android平板运行时,
TDialogService.ShowMessage(fn)显示路径正确:\\DRIVE-ABC\Pictures\123456.jpg,但执行.LoadFromFile(fn)时报错:
Cannot open file "/\\DRIVE-ABC\Pictures\123456.jpg". Not a directory.
针对两个怀疑点的解决办法
1. 路径格式问题(开头多正斜杠)
Android基于Linux内核,使用POSIX路径规范,不直接支持Windows的UNC路径(\\服务器\共享\文件格式)。Delphi的LoadFromFile在Android平台会调用原生文件API,该API会将UNC路径错误解析为相对路径,自动在开头添加/,导致路径无效。
解决方式:将UNC路径转换为SMB协议的URL格式,再通过流的方式加载图片(因为LoadFromFile不支持SMB协议路径):
procedure TForm1.ShowPicture; var fn: string; smbUrl: string; httpClient: THTTPClient; stream: TMemoryStream; begin BitMapPath := '\\DRIVE-ABC\Pictures\'; qryPictures.Open; qryPictures.First; if not(qryPictures.FindField('Picture').IsNull) then begin fn := BitMapPath + qryPictures.FieldByName('Picture').AsString; // 转换UNC路径为SMB URL格式 smbUrl := StringReplace(fn, '\\', 'smb://', [rfReplaceAll]); smbUrl := StringReplace(smbUrl, '\', '/', [rfReplaceAll]); // 通过流加载图片(需处理认证,见下文) httpClient := THTTPClient.Create; stream := TMemoryStream.Create; try // 这里需要添加SMB认证信息,参考下文 httpClient.Get(smbUrl, stream); stream.Position := 0; imgPart.Bitmap.LoadFromStream(stream); finally stream.Free; httpClient.Free; end; end; end;
2. 网络共享认证问题
Android设备访问Windows共享时,无法像Windows那样自动弹出凭据输入框,必须在代码中手动传入共享的用户名和密码。
推荐使用支持SMB协议的Delphi组件(如Indy的TIdSMB)来处理认证和文件读取:
procedure TForm1.ShowPicture; var fn: string; smb: TIdSMB; memStream: TMemoryStream; begin BitMapPath := '\\DRIVE-ABC\Pictures\'; qryPictures.Open; qryPictures.First; if not(qryPictures.FindField('Picture').IsNull) then begin fn := qryPictures.FieldByName('Picture').AsString; smb := TIdSMB.Create(nil); memStream := TMemoryStream.Create; try // 设置共享服务器地址、凭据 smb.Host := 'DRIVE-ABC'; smb.Username := '共享用户名'; smb.Password := '共享密码'; smb.Connect; // 打开共享目录,读取文件到内存流 smb.GetFile('Pictures', fn, memStream); memStream.Position := 0; // 加载到TImage imgPart.Bitmap.LoadFromStream(memStream); finally smb.Disconnect; memStream.Free; smb.Free; end; end; end;
另外,需确保AndroidManifest.xml中添加了网络权限:
<uses-permission android:name="android.permission.INTERNET" />
内容的提问来源于stack exchange,提问作者Mark Lyder
相关产品推荐
相关产品推荐

