如何将SD卡/外部存储文件上传至服务器?遇权限拒绝报错求解决
解决外部SD卡文件上传权限被拒的问题
这个坑我之前踩过!你遇到的java.io.FileNotFoundException:/mnt/media_rw/:/open failed: EACCESS(Permission denied)错误,核心原因是Android 10及以上版本的分区存储(Scoped Storage)限制,再加上你用的MediaStore.Files.FileColumns.DATA字段在高版本系统里已经被废弃,直接拿路径访问外部SD卡文件会被系统拦截——哪怕你在Manifest里加了权限也没用。
为什么原来的方法行不通?
- 分区存储限制:Android 10开始,应用只能直接访问自己沙箱内的文件,外部SD卡的文件属于公共存储,必须通过
ContentResolver或者DocumentFile来操作,直接用路径打开会触发权限拒绝。 - DATA字段废弃:
MediaStore.Files.FileColumns.DATA在Android Q之后被标记为废弃,返回的路径要么无效,要么没有实际访问权限,尤其是外部SD卡的文件。
推荐解决方案:直接通过Uri读取文件流上传(最稳妥)
放弃获取真实路径的思路,改用ContentResolver.openInputStream()直接读取文件内容,绕开路径访问的权限问题,这也是符合Android现代存储规范的做法。
示例代码:
private void uploadFileViaUri(Uri fileUri) { try { // 通过ContentResolver获取文件输入流 InputStream fileInputStream = getContentResolver().openInputStream(fileUri); if (fileInputStream == null) { // 处理文件获取失败的情况 return; } // 这里以OkHttp为例实现上传,你可以替换成自己的上传逻辑 RequestBody requestBody = RequestBody.create( MediaType.parse("application/octet-stream"), fileInputStream ); Request uploadRequest = new Request.Builder() .url("你的服务器上传接口地址") .post(requestBody) .build(); OkHttpClient client = new OkHttpClient(); client.newCall(uploadRequest).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // 上传失败的处理逻辑 e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { // 上传成功的处理逻辑 } else { // 上传返回错误的处理逻辑 } response.close(); } }); } catch (IOException e) { e.printStackTrace(); } }
额外注意事项
- 动态权限申请:即使Manifest里加了权限,Android 6.0+还需要动态申请对应权限:
- Android 12及以下:
READ_EXTERNAL_STORAGE - Android 13及以上:根据文件类型申请
READ_MEDIA_IMAGES/READ_MEDIA_VIDEO/READ_MEDIA_AUDIO
- Android 12及以下:
- 不要试图绕开分区存储限制(比如用
requestLegacyExternalStorage),这只是临时方案,后续版本会被彻底禁用。
内容的提问来源于stack exchange,提问作者Gowri
相关产品推荐
相关产品推荐

