You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android保存图片到外部存储子目录时触发FileNotFound异常

Android 截图保存到多层子目录时报EISDIR异常

问题相关代码

private fun takeScreenshot() {
    val now = Date()
    val formattedTimestamp = DateFormat.format("yyyy-MM-dd_hh:mm:ss", now)
    try {
        // 直接存外部存储根目录:运行正常
        //val mPath : String = Environment.getExternalStorageDirectory().toString() + "/" + formattedTimestamp + ".jpg"
        // 存多层自定义子目录:抛出异常
        val mPath: String = Environment.getExternalStorageDirectory().toString() + "/mobile/" + GetSetContext.getApplicationName() + "/Screenshots/" + formattedTimestamp + ".jpg"

        val v = this.view!!
        v.setDrawingCacheEnabled(true)
        v.buildDrawingCache(true)
        val bitmap: Bitmap = Bitmap.createBitmap(v.getDrawingCache())
        v.setDrawingCacheEnabled(false)
        val imageFile = File(mPath)
        val outputStream = FileOutputStream(imageFile)
        val quality = 100
        bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream)
        outputStream.flush()
        outputStream.close()
        ScreenshotUploadWorkManager().setupUploadingRequest(context, applicationConfiguration,mPath)
    }
}

异常信息

java.io.FileNotFoundException: /storage/emulated/0/mobile/App/Screenshots/2022-06-20_09:00:18.jpg: open failed: EISDIR (Is a directory)

已通过Android Studio Device File Explorer手动创建路径对应所有子目录,问题仍复现。

问题原因与修复方案

  • 报错EISDIR (Is a directory)的直接原因:你要写入的目标路径2022-06-20_09:00:18.jpg实际是个同名目录,不是文件。大概率是你手动创建目录的时候,误把最后一级的jpg文件名也建成了文件夹,直接去Device File Explorer里进入Screenshots目录,找到这个和截图同名的.jpg后缀文件夹删掉即可。
  • 代码存在逻辑疏漏:绝对不能依赖手动创建目录,App运行时必须主动校验、递归创建父目录,否则换设备、清存储、改路径都会触发路径不存在的问题。在创建FileOutputStream之前加入如下逻辑:
val imageFile = File(mPath)
// 递归创建所有不存在的父目录
imageFile.parentFile?.takeIf { !it.exists() }?.mkdirs()
// 兜底处理:如果目标路径已存在且是目录,先删除错误的目录项
if (imageFile.exists() && imageFile.isDirectory) {
    imageFile.delete()
}
val outputStream = FileOutputStream(imageFile)
  • 版本适配遗漏:如果你的App targetSdkVersion >= 29(对应Android 10及以上),系统默认开启分区存储,直接访问外部存储公共根目录会被权限拦截。要么在AndroidManifest的<application>标签下加android:requestLegacyExternalStorage="true"临时兼容,要么改用App私有存储目录、MediaStore API来保存截图,避免权限问题。
  • 额外注意:你拼接路径时用的时间戳格式里带冒号:,部分安卓版本对存储文件的文件名有特殊字符限制,建议把时间格式里的冒号改成下划线,比如yyyy-MM-dd_hh_mm_ss,避免其他机型上出现文件名非法的问题。

内容的提问来源于stack exchange,提问作者Mithun Wijethunga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 10:51:21