Android应用多文件导入问题:CSV相对路径读取图片失败
Android导入图片时Uri转File导致文件未找到的解决方案
问题根因
Android 10及以上的分区存储限制,加上通过文件选择器获取的Uri通常来自Storage Access Framework(SAF),这类Uri的getPath()返回的并非真实文件系统路径(比如格式为/document/primary:XXX/import.csv),直接用这个路径创建File对象自然会找不到文件。
导入端正确实现(无需修改导出端)
放弃Uri转File的思路,改用ContentResolver直接通过Uri操作文件,步骤如下:
- 读取CSV文件内容:通过
ContentResolver.openInputStream()获取CSV的输入流,解析其中的相对路径。 - 构建图片的SAF Uri:从CSV的Uri解析出父目录的文档ID,再拼接图片的相对路径生成图片的Uri。
- 复制图片到目标目录:用
ContentResolver.openInputStream()打开图片流,复制到应用的私有存储目录。
代码示例
// 假设已经获取到import.csv的Uri:csvUri File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); if (storageDir == null) return; // 读取CSV文件 try (InputStream csvInputStream = getContentResolver().openInputStream(csvUri); BufferedReader reader = new BufferedReader(new InputStreamReader(csvInputStream))) { String line; while ((line = reader.readLine()) != null) { String relativeImagePath = line.trim(); if (relativeImagePath.isEmpty()) continue; // 解析CSV所在父目录的Document ID String csvDocId = DocumentsContract.getDocumentId(csvUri); String[] docIdParts = csvDocId.split(":", 2); if (docIdParts.length != 2) continue; String authority = csvUri.getAuthority(); String rootId = docIdParts[0]; String csvRelativePath = docIdParts[1]; String parentRelativePath = new File(csvRelativePath).getParent(); if (parentRelativePath == null) continue; // 构建父目录的Uri String parentDocId = rootId + ":" + parentRelativePath; Uri parentDirUri = DocumentsContract.buildDocumentUriUsingTree(csvUri, parentDocId); // 构建图片的Uri String imageDocId = parentDocId + "/" + relativeImagePath; Uri imageUri = DocumentsContract.buildDocumentUriUsingTree(parentDirUri, imageDocId); // 复制图片到目标目录 try (InputStream imageInputStream = getContentResolver().openInputStream(imageUri); FileOutputStream outputStream = new FileOutputStream(new File(storageDir, new File(relativeImagePath).getName()))) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = imageInputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } } catch (IOException e) { e.printStackTrace(); } } } catch (IOException e) { e.printStackTrace(); }
导出端优化建议(更可靠)
如果可以调整导出逻辑,推荐以下两种方式:
- 打包为Zip文件:把
import.csv和importFolder一起打包成zip。应用获取zip的Uri后,直接解压到私有存储目录,再读取CSV和图片,完全避免相对路径和SAF的适配问题。 - CSV中存储图片的SHA-1哈希:导出时计算每个图片的哈希值并写入CSV,导入时扫描指定目录匹配哈希找图片(适合批量导入场景)。
注意事项
- 确保用户通过文件选择器选择
import.csv时,应用已获得该文件及父目录的访问权限(SAF会自动授权所选文件及子文件)。 - 避免直接操作外部存储的绝对路径,优先使用应用私有存储(
getExternalFilesDir())或SAF。
内容的提问来源于stack exchange,提问作者Ace of Spade
相关产品推荐
相关产品推荐

