Android中从PDF文件URI获取真实路径报错,如何解决?
问题描述
我想从PDF文件的URI获取真实路径,实现代码如下:
文件处理代码
@NonNull private MultipartBody.Part prepareFilePart(Uri fileUri) { File file = new File(getPDFPath(fileUri)); RequestBody requestFile = RequestBody.create(MediaType.parse("*/*"),file); return MultipartBody.Part.createFormData("pdf", file.getName(), requestFile); } public String getPDFPath(Uri uri){ final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.parseLong(id)); String[] projection = { MediaStore.Images.Media.DATA }; Cursor cursor = getContentResolver().query(contentUri, projection, null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); return cursor.getString(column_index); }
URI获取代码
ActivityResultLauncher<Intent> intentresultlauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { Intent data = result.getData(); if(data != null){ Uri pdf_data = data.getData(); prepareFilePart(pdf_data); } } } ); button.setOnClickListener(view -> { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("application/pdf"); intentresultlauncher.launch(intent); });
运行时出现错误:
java.lang.NumberFormatException: For input string: "document:1000011543"
请问哪里出错了?该如何解决?或者有没有其他获取文件真实路径的方法?
错误原因分析
- 数字格式异常直接原因:
DocumentsContract.getDocumentId(uri)返回的字符串是document:1000011543,直接用Long.parseLong(id)转换时,前缀document:会导致数字格式解析失败。 - 隐藏适配问题:
- 硬编码
content://downloads/public_downloads仅适用于系统下载目录的文件,但ACTION_OPEN_DOCUMENT返回的URI可能来自第三方文件管理器、云存储等其他提供者,通用性极差。 - 使用
MediaStore.Images.Media.DATA字段获取路径已过时,Android 10及以上版本受Scoped Storage限制,该字段可能返回空或无法访问的路径。
- 硬编码
解决方法
方案1:修复当前路径获取逻辑(仅适用于下载目录文件)
先剥离文档ID的前缀,再做数字转换,同时修正MediaStore字段:
public String getPDFPath(Uri uri){ String id = DocumentsContract.getDocumentId(uri); // 剥离"document:"前缀,提取纯数字ID if (id.startsWith("document:")) { id = id.split(":")[1]; } final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.parseLong(id)); // 用MediaStore.Downloads而非Images,匹配PDF文件类型 String[] projection = { MediaStore.Downloads.DATA }; Cursor cursor = getContentResolver().query(contentUri, projection, null, null, null); if (cursor == null) return null; int column_index = cursor.getColumnIndexOrThrow(MediaStore.Downloads.DATA); cursor.moveToFirst(); String path = cursor.getString(column_index); cursor.close(); // 关闭Cursor避免内存泄漏 return path; }
方案2:通过文件流创建临时文件(通用推荐)
Android 10+官方不建议直接获取文件真实路径,更安全的方式是通过ContentResolver读取文件流,转换为临时文件后用于Multipart请求:
@NonNull private MultipartBody.Part prepareFilePart(Uri fileUri) throws IOException { // 获取文件名 String fileName = getFileName(fileUri); // 在缓存目录创建临时PDF文件 File tempFile = File.createTempFile("temp_pdf", ".pdf", getCacheDir()); // 将Content URI的文件流复制到临时文件 try (InputStream inputStream = getContentResolver().openInputStream(fileUri); FileOutputStream outputStream = new FileOutputStream(tempFile)) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } } // 构建Multipart请求体 RequestBody requestFile = RequestBody.create(MediaType.parse("application/pdf"), tempFile); return MultipartBody.Part.createFormData("pdf", fileName, requestFile); } // 从Content URI获取文件名的辅助方法 private String getFileName(Uri uri) { String fileName = null; Cursor cursor = getContentResolver().query(uri, null, null, null, null); if (cursor != null) { cursor.moveToFirst(); fileName = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)); cursor.close(); } return fileName != null ? fileName : "unknown.pdf"; }
该方案优势:
- 适配所有
ACTION_OPEN_DOCUMENT返回的URI,包括云存储、第三方文件管理器文件 - 符合Android 10+的Scoped Storage规范,无需额外文件权限
- 避免路径获取失败的兼容性问题
额外注意事项
- 使用临时文件后,建议在请求完成后调用
tempFile.delete()清理缓存,避免占用空间。 - 若minSdkVersion >=29,可尝试使用
MediaStore.Downloads.RELATIVE_PATH替代DATA字段,但流转换方案通用性更强。
内容的提问来源于stack exchange,提问作者user21917572
相关产品推荐
相关产品推荐

