Firemonkey Android读取大于1MB的InputStream返回0问题求助
问题原因
- 第三方文件管理应用提供的FileProvider返回的InputStream存在兼容缺陷,调用
available()获取大文件长度时会触发缓冲区预读,指针未正确复位,导致后续读取内容前出现多段0值。 - 代码直接用Delphi默认的2字节
Char接收Java InputStream返回的单字节值,虽然小文件场景下显示正常,但存在高位补0的隐藏问题,容易和实际读取到的0值混淆。 - Firemonkey 10.4.1版本对Android原生InputStream的直接调用存在已知的小概率读取偏移bug,单字节读取模式在大文件场景下兼容性更差。
解决方案
按照以下规则修改代码即可解决问题:
- 调整读取顺序,优先读取文件内容,后获取文件长度,避免
available()调用对读取指针的影响 - 用
Byte类型接收单字节读取结果,避免宽字符类型干扰 - 使用Firemonkey提供的
TJavaInputStream包装原生JInputStream,转换成Delphi标准流操作,兼容性更高
修改后的可运行参考代码:
uses Androidapi.Helpers, Androidapi.JNI.JavaTypes, Androidapi.JNI.Net, System.Classes, Androidapi.JNI.GraphicsContentViewText; function StartupFileGet : string; var intent: JIntent; uri: Jnet_Uri; uriStr: String; InStrm: JInputStream; delphiStream: TStream; buf: array[0..1] of Byte; readCount: Integer; total: integer; begin Result := ''; intent := TAndroidHelper.Activity.getIntent; if intent = nil then Exit; if TJIntent.JavaClass.ACTION_VIEW.equals(intent.getAction) then begin uri := intent.getData; uriStr := JStringToString(uri.toString); Result := uriStr + '='; InStrm := TAndroidHelper.Activity.getContentResolver.openInputStream(uri); if InStrm = nil then Exit; try delphiStream := TJavaInputStream.Create(InStrm); try // 先读取前2字节,不提前调用长度获取接口 readCount := delphiStream.Read(buf, 2); if readCount = 2 then begin Result := Result + Chr(buf[0]) + Chr(buf[1]); end; // 最后获取总长度 total := delphiStream.Size; Result := Result + ', ' + IntToStr(total); finally delphiStream.Free; end; except Result := Result + ', exception'; end; InStrm.close; end; end;
修改后测试大文件即可正常读取到PK的zip头标识,不会出现前导0的问题。
内容的提问来源于stack exchange,提问作者rondowe
相关产品推荐
相关产品推荐

