Android 11中使用File API访问存储遇权限及文件列表问题
在多台Android 11设备上遇到外部存储读写异常情况。已知Android 10/11有存储机制改动,但原本预期应用可无阻碍访问自身专属的内部及外部目录,现寻求解决建议。
设备1:写入可移除外部存储卡抛出EPERM错误
执行以下代码向可移除外部存储卡写入时,抛出EPERM (Operation not permitted)错误:
val externalDirectories = applicationContext.getExternalFilesDirs(null) externalFile = File(externalDirectories[1].path + "/sampletextfile.txt") externalFile.writeText("sample text")
堆栈跟踪信息:
java.io.IOException: close failed: EPERM (Operation not permitted)
at libcore.io.IoBridge.closeAndSignalBlockedThreads(IoBridge.java:254)
at java.io.FileOutputStream.close(FileOutputStream.java:431)
at java.io.FileOutputStream.finalize(FileOutputStream.java:500)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:291)
at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:278)
at java.lang.Daemons$Daemon.run(Daemons.java:139)
at java.lang.Thread.run(Thread.java:923)
Caused by: android.system.ErrnoException: close failed: EPERM (Operation not permitted)
at libcore.io.Linux.close(Native Method)
at libcore.io.ForwardingOs.close(ForwardingOs.java:88)
at libcore.io.BlockGuardOs.close(BlockGuardOs.java:110)
at libcore.io.ForwardingOs.close(ForwardingOs.java:88)
at libcore.io.IoBridge.closeAndSignalBlockedThreads(IoBridge.java:252)
at java.io.FileOutputStream.close(FileOutputStream.java:431)
at java.io.FileOutputStream.finalize(FileOutputStream.java:500)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:291)
at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:278)
at java.lang.Daemons$Daemon.run(Daemons.java:139)
at java.lang.Thread.run(Thread.java:923)
设备2:写入成功但无法读取目录文件列表
可成功执行上述写入代码,但无法获取目录文件列表:
- 以下代码始终返回
false:
externalDirectories[1].canRead()
- 即便目录中有文件,以下代码始终返回
null:
externalDirectories[1].listFiles()
解决建议
- 检查存储卡状态:确认可移除存储卡已正确挂载,无只读锁定或硬件故障。部分设备对存储卡文件系统格式有要求(如FAT32/exFAT),格式不兼容可能引发权限异常。
- 规范路径构建:避免手动拼接路径,改用
File构造方法生成文件对象,例如File(externalDirectories[1], "sampletextfile.txt"),减少路径错误导致的权限问题。 - 校验目录有效性:操作前先判断
externalDirectories[1]是否为null,部分设备未插入存储卡时该目录不存在,直接操作会触发异常。 - 排查权限配置:尽管Android 11中应用访问自身专属外部目录无需
WRITE_EXTERNAL_STORAGE权限,但部分定制ROM可能存在管控差异,可在Manifest中声明该权限并尝试动态申请(Android 11会自动忽略该权限申请)。 - 尝试SAF替代方案:若专属目录操作仍异常,可通过存储访问框架(SAF)获取应用专属目录的Uri进行读写操作;若涉及非专属目录,必须通过SAF让用户授权访问。
- 适配定制ROM差异:不同品牌的Android 11定制ROM可能有特殊存储实现,部分厂商对可移除存储卡的应用专属目录额外限制,可参考对应厂商的开发者文档或社区反馈。
内容的提问来源于stack exchange,提问作者WVDev77

