Android如何使用FileOutputStream编辑/修改Uri引用的文件
问题解答
问题1:是否有其他选取文件的方式可以直接获取文件的真实路径?
- Android 10(API 29)起分区存储机制正式落地,官方已禁止普通应用随意访问外部存储的任意文件路径,哪怕你通过各种适配方法拿到了所谓的「真实路径」,绝大多数场景下也会因为没有文件访问权限导致读写失败。
- 所有依赖真实路径的文件操作方案在高版本安卓系统上都存在兼容性问题,官方推荐的操作方式就是直接使用Uri进行文件读写,不要强行获取真实路径。
问题2:如果无法获取文件路径,如何不使用getPath()或路径字符串,直接通过Uri写入文件?
安卓系统提供了ContentResolver类来处理Uri对应的文件操作,你可以直接调用ContentResolver.openOutputStream()方法获取输出流写入数据,无需路径字符串。
首先建议你把文件选择器的启动Intent从ACTION_GET_CONTENT换成ACTION_OPEN_DOCUMENT,后者可以获取到选中文件的长期读写权限,更适合修改文件的场景:
public void openFileChooser() { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("*/*"); someActivityResultLauncher.launch(intent); }
然后修改写入方法,直接接收Uri作为参数:
void writeToFile(Uri uri, String data, Context context) { try (OutputStream outputStream = context.getContentResolver().openOutputStream(uri)) { outputStream.write(data.getBytes()); Toast.makeText(context, "SAVED", Toast.LENGTH_LONG).show(); } catch (IOException e) { Toast.makeText(context, "File write failed: " + e.toString(), Toast.LENGTH_LONG).show(); } }
在onActivityResult拿到Uri之后直接调用writeToFile(uri, 要写入的内容, context)即可。如果需要长期访问该文件,可以在拿到Uri后调用以下代码申请持久化权限,避免后续访问被拒绝:
context.getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
问题3:在仅持有Uri的场景下,是否有办法将Uri与FileOutputStream搭配使用?
可以的,你可以先通过ContentResolver获取Uri对应的FileDescriptor,再用FileDescriptor构造FileOutputStream,示例代码如下:
void writeToFileWithFileOutputStream(Uri uri, String data, Context context) { ParcelFileDescriptor pfd = null; FileOutputStream outputStream = null; try { // 第二个参数"w"代表覆盖写入,"wa"代表追加写入,可按需调整 pfd = context.getContentResolver().openFileDescriptor(uri, "w"); if (pfd != null) { outputStream = new FileOutputStream(pfd.getFileDescriptor()); outputStream.write(data.getBytes()); Toast.makeText(context, "SAVED", Toast.LENGTH_LONG).show(); } } catch (IOException e) { Toast.makeText(context, "File write failed: " + e.toString(), Toast.LENGTH_LONG).show(); } finally { try { if (outputStream != null) { outputStream.close(); } if (pfd != null) { pfd.close(); } } catch (IOException e) { e.printStackTrace(); } } }
内容的提问来源于stack exchange,提问作者SWIK
相关产品推荐
相关产品推荐

