Android 13文档选择读取异常:文件存在检测失败的排查方法
问题根源与解决方案
为什么路径获取始终失败?
SAF(存储访问框架)返回的content://类型URI不是本地文件系统的真实路径,它指向的是系统文档提供者管理的资源,和传统的file:// URI完全不同:
- 调用
fileUri.path得到的只是URI的路径段,并非真实文件路径,自然会提示文件不存在; - 常规的PathUtils类仅适配
file://URI,无法解析SAF的content://URI,所以返回null。
正确的文件存在性检测方式
不要用File类或路径判断,直接通过ContentResolver验证:
// 方式1:尝试打开输入流验证 public boolean isDocumentExists(Context context, Uri uri) { try { InputStream inputStream = context.getContentResolver().openInputStream(uri); if (inputStream != null) { inputStream.close(); return true; } } catch (FileNotFoundException e) { return false; } catch (IOException e) { e.printStackTrace(); } return false; }
// 方式2:查询文档元数据验证 public boolean isDocumentExists(Context context, Uri uri) { String[] projection = {DocumentsContract.Document.COLUMN_DOCUMENT_ID}; Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null); boolean exists = cursor != null && cursor.getCount() > 0; if (cursor != null) cursor.close(); return exists; }
无需全文件访问权限的文档读取方式
直接使用SAF配套API通过ContentResolver操作,无需申请READ_EXTERNAL_STORAGE或MANAGE_EXTERNAL_STORAGE权限:
读取单个文件(ACTION_OPEN_DOCUMENT返回的URI)
public String readDocumentContent(Context context, Uri uri) throws IOException { StringBuilder content = new StringBuilder(); InputStream inputStream = context.getContentResolver().openInputStream(uri); if (inputStream != null) { BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { content.append(line); } inputStream.close(); reader.close(); } return content.toString(); }
遍历并读取目录下文件(ACTION_OPEN_DOCUMENT_TREE返回的URI)
用DocumentFile处理目录:
public void traverseTreeUri(Context context, Uri treeUri) { DocumentFile rootDir = DocumentFile.fromTreeUri(context, treeUri); if (rootDir != null && rootDir.isDirectory()) { for (DocumentFile file : rootDir.listFiles()) { if (file.isFile()) { try { String content = readDocumentContent(context, file.getUri()); // 处理文件内容 } catch (IOException e) { e.printStackTrace(); } } else if (file.isDirectory()) { traverseTreeUri(context, file.getUri()); } } } }
额外注意事项
- 若需长期访问选中的文档,需调用
getContentResolver().takePersistableUriPermission(uri, intent.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION))保存权限,否则重启App后会失去访问权限; - 不要尝试将
content://URI转换为真实文件路径,Android 10+对此有严格限制,且SAF的API完全能满足文件读写需求。
内容的提问来源于stack exchange,提问作者Tariq Hussain
相关产品推荐
相关产品推荐

