已存在文件仍报File does not exist异常的Android开发问题
问题原因分析
你遇到的核心问题是混淆了Content URI和本地文件路径:
- 通过
ACTION_OPEN_DOCUMENT获取的Uri是Content URI(格式为content://xxx),它指向系统文件管理器提供的内容,并非本地文件系统的真实路径。 - 直接用
uri.getPath()创建File对象,File类无法解析这种Content URI,自然会判断文件不存在。
代码错误点
- 错误的URI转File方式:
new File(uri.getPath())完全无效,因为uri.getPath()在这里返回的是/com.android.externalstorage.documents/document/primary%3Aestonia.map,这不是本地文件系统的路径。 - 权限调用顺序问题:
takePersistableUriPermission应该在尝试访问文件前调用,但这不是导致文件不存在的直接原因。
修复方案
根据openMap()方法的参数要求,有两种修复方式:
方式一:直接使用InputStream(推荐)
如果openMap()可以接受InputStream,直接通过ContentResolver打开流:
final ActivityResultLauncher<Intent> sARL = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { if (result.getResultCode() == Activity.RESULT_OK){ Intent data = result.getData(); assert data != null; Uri uri = data.getData(); // 先获取持久权限 getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); try { // 打开输入流 InputStream inputStream = getContentResolver().openInputStream(uri); // 假设openMap支持InputStream参数,调整方法参数即可 openMap(inputStream); } catch (IOException e) { Log.e("File", "Failed to open file stream", e); } } } });
方式二:复制到应用私有目录(如果必须用File对象)
如果openMap()只能接受File对象,需要将Content URI对应的文件复制到应用的私有存储目录,再使用这个本地文件:
final ActivityResultLauncher<Intent> sARL = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { if (result.getResultCode() == Activity.RESULT_OK){ Intent data = result.getData(); assert data != null; Uri uri = data.getData(); getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); try { // 创建应用私有目录下的临时文件 File localFile = new File(getFilesDir(), "temp_map.map"); // 复制文件内容 try (InputStream in = getContentResolver().openInputStream(uri); OutputStream out = new FileOutputStream(localFile)) { byte[] buffer = new byte[1024]; int length; while ((length = in.read(buffer)) > 0) { out.write(buffer, 0, length); } } // 现在可以用这个本地文件调用openMap if (localFile.exists()) { openMap(localFile); } } catch (IOException e) { Log.e("File", "Failed to copy file", e); } } } });
额外说明
ACTION_OPEN_DOCUMENT是基于内容提供者的文件选择方式,不要试图将其转换为真实文件路径,这在Android 10+的分区存储机制下是被限制的。- 持久权限
takePersistableUriPermission确保你在重启应用后仍能访问该文件,这部分是正确的,但要注意调用时机。
内容的提问来源于stack exchange,提问作者Topstiks
相关产品推荐
相关产品推荐

