Android开发:如何获取多选PDF文件的真实本地路径?
Android多选PDF文件获取真实本地路径解决方案
问题背景
单选PDF文件时,可通过String path = data.getData().getPath();获取真实路径,但多选场景下只能拿到每个PDF的URI,无法直接转换为真实本地路径。以下是原始代码:
private void selectPDFs() { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("application/pdf"); intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); someActivityResultLauncher.launch(intent); } ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { if (result.getResultCode() == Activity.RESULT_OK) { Intent data = result.getData(); if (data != null) { if (data.getClipData() != null) { int count = data.getClipData().getItemCount(); int cItem = 0; while (cItem < count) { String uri = data.getClipData().getItemAt(cItem).getUri().toString(); File f = new File(uri); // 此处需要真实路径而非URI files.add(f); // files是ArrayList<File> cItem++; } } else if (data.getData() != null) { String path = data.getData().getPath(); // path是真实文件路径 File f = new File(path); files.add(f); } } } } });
解决方案
Android中通过ACTION_GET_CONTENT获取的URI多为content://格式,并非直接的文件系统路径,不能直接用File(uri)转换。需通过ContentResolver查询媒体数据库或读取文件流来获取真实路径,以下是具体实现:
- 编写工具方法获取真实路径
private String getRealPathFromUri(Context context, Uri uri) { String realPath = null; // 针对不同Android版本适配 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // Android 10及以上,通过文件流复制到应用私有目录使用 try (InputStream inputStream = context.getContentResolver().openInputStream(uri)) { File tempFile = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), "temp_" + System.currentTimeMillis() + ".pdf"); try (OutputStream outputStream = new FileOutputStream(tempFile)) { byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, length); } realPath = tempFile.getAbsolutePath(); } } catch (IOException e) { e.printStackTrace(); } } else { // Android 9及以下,查询媒体数据库获取路径 String[] projection = {MediaStore.Files.FileColumns.DATA}; Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null); if (cursor != null) { if (cursor.moveToFirst()) { int columnIndex = cursor.getColumnIndex(projection[0]); realPath = cursor.getString(columnIndex); } cursor.close(); } } return realPath; }
- 修改多选逻辑调用工具方法
将多选部分的代码替换为调用上述方法获取真实路径:
if (data.getClipData() != null) { int count = data.getClipData().getItemCount(); int cItem = 0; while (cItem < count) { Uri pdfUri = data.getClipData().getItemAt(cItem).getUri(); String realPath = getRealPathFromUri(this, pdfUri); if (realPath != null) { File f = new File(realPath); files.add(f); } cItem++; } }
注意事项
- Android 10及以上采用分区存储,直接获取原始文件路径可能受限,复制到应用私有目录可避免权限问题。
- 需在
AndroidManifest.xml中声明权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 13及以上需添加 --> <uses-permission android:name="android.permission.READ_MEDIA_DOCUMENTS" />
- 调用选择文件方法前,需动态申请相应权限。
内容的提问来源于stack exchange,提问作者raul g h
相关产品推荐
相关产品推荐

