File.delete()在Android上对缓存图片常无效,因其仅做元数据清理,不处理只读属性、文件占用、权限限制及媒体库残留;须配合预检查、权限设置、存在校验与媒体扫描方可可靠删除。

File.delete() 本身不安全,直接调用大概率失败或静默失效,尤其在 Android 10+ 和共享存储场景下。 它只做一次性元数据清理,不处理只读属性、占用状态、权限限制或媒体数据库残留,必须配合预检查和兜底逻辑才能用于缓存图片清理。
Android 上 File.delete() 为什么对缓存图片经常无效
从 Android 5.0(L)起,File.delete() 对外部存储(如 /sdcard/Android/data/ 以外路径)基本失效;即使返回 true,物理文件可能仍在,只是媒体库没刷新。更常见的是直接返回 false,且不抛异常——你根本不知道它没删成。
- 目标路径是
getExternalCacheDir()以外的目录(比如手动建的/sdcard/MyApp/cache/),系统会拒绝写入 - 图片正被
ImageView、Glide或其他线程持有输入流,文件句柄未释放 - 文件属性为
READ_ONLY(某些下载库保存时默认设此属性) - 目标在 Scoped Storage 管控区,
FileAPI 完全无权访问,必须走MediaStore或Storage Access Framework
真正能落地的缓存图片删除流程
不要幻想单行 file.delete() 解决问题。缓存图片清理必须分三步:确认可删 → 尝试删 → 验证并兜底。
- 先用
file.exists()和file.isFile()排除空路径或目录误删 - 调用
file.setReadable(true, false)和file.setWritable(true, false)确保权限可写(尤其从AssetManager拷出的文件) - 若
file.getCanonicalPath().contains("Android/data"),优先走context.deleteFile()或context.getExternalFilesDir(null)下的子路径,这类路径受沙箱保护但删除稳定 - 删完立刻用
!file.exists()校验;若仍存在,说明被占用或权限不足,此时应记录日志,而非重试——重试大概率卡死 - 如果是通过
MediaStore.Images.Media.insertImage()写入的图片,必须额外调用ContentResolver.delete()清媒体库条目,否则图库 App 里还能看到“幽灵缩略图”
替代方案:比 File.delete() 更可靠的两个选择
当缓存图片路径不可控(比如用户相册选图后存到公共 DCIM 目录),File.delete() 应该被放弃,改用平台级接口。
- 对 Android 10+ 的公共图片,用
MediaStore删除:ContentResolver resolver = context.getContentResolver(); Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id); resolver.delete(uri, null, null);
注意:这只会删媒体库记录,物理文件是否删掉取决于系统策略,但至少保证图库不再显示 - 对需要用户授权的路径(如 SD 卡根目录),必须用
Storage Access Framework获取持久 URI 权限,再调用DocumentsContract.deleteDocument()—— 这是唯一能稳定删掉content://URI 所指文件的方式,File对象在这里完全无用
最常被忽略的一点:缓存图片删除不是“删完就完”,而是“删完后立刻触发媒体扫描”。否则新图片写入同名路径时,旧缩略图可能残留数分钟。别依赖 MediaScannerConnection.scanFile(),它不保证顺序;更稳妥的是监听 Intent.ACTION_MEDIA_SCANNER_STARTED 后再继续后续逻辑。










