记一个 Andorid 生成文件失败的bug
Android生成文件失败:java.lang.IllegalStateException:Failed to build unique file: /storage/emulated/0/...
1.问题来源
App 调用相机拍照,中间有一些处理过程,然后将这张照片插入系统图片数据库中。
MediaStore.Images.Media.insertImage(getContentResolver(), photoPath, null, null);
很长一段时间,这段代码都运行的好好的,可是突然有一天,测试妹妹报告一个bug,拍照之后,保存图片失败了,并且在 Gallery 中也看不到这张图片。
幸运地是,专业的测试妹妹,抓到了Log,很快找到了错误地方:
E DatabaseUtils: Writing exception to parcel
E DatabaseUtils: java.lang.IllegalStateException: Failed to build unique file: /storage/emulated/0/Pictures/Image.jpg bucket_display_name=Pictures volume_name=external_primary date_modified=null date_expires=null _display_name=Image.jpg mime_type=image/jpeg _data=/storage/emulated/0/Pictures/Image.jpg _size=null is_trashed=0 is_pending=0 bucket_id=-1617409521 relative_path=Pictures/
E DatabaseUtils: at com.android.providers.media.MediaProvider.ensureFileColumns(MediaProvider.java:2624)
E DatabaseUtils: at com.android.providers.media.MediaProvider.ensureUniqueFileColumns(MediaProvider.java:2368)
E DatabaseUtils: at com.android.providers.media.MediaProvider.updateInternal(MediaProvider.java:5265)
E DatabaseUtils: at com.android.providers.media.MediaProvider.update(MediaProvider.java:4953)
E DatabaseUtils: at android.content.ContentProvider$Transport.update(ContentProvider.java:457)
E DatabaseUtils: at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:230)
E DatabaseUtils: at android.os.Binder.execTransactInternal(Binder.java:1159)
E DatabaseUtils: at android.os.Binder.execTransact(Binder.java:1123)
W MediaStore: Failed to insert image
W MediaStore: java.lang.IllegalStateException: Failed to build unique file: /storage/emulated/0/Pictures/Image.jpg bucket_display_name=Pictures volume_name=external_primary date_modified=null date_expires=null _display_name=Image.jpg mime_type=image/jpeg _data=/storage/emulated/0/Pictures/Image.jpg _size=null is_trashed=0 is_pending=0 bucket_id=-1617409521 relative_path=Pictures/
W MediaStore: at android.os.Parcel.createExceptionOrNull(Parcel.java:2381)
W MediaStore: at android.os.Parcel.createException(Parcel.java:2357)
W MediaStore: at android.os.Parcel.readException(Parcel.java:2340)
W MediaStore: at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:190)
W MediaStore: at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)
W MediaStore: at android.content.ContentProviderProxy.update(ContentProviderNative.java:649)
W MediaStore: at android.content.ContentResolver.update(ContentResolver.java:2356)
W MediaStore: at android.content.ContentResolver.update(ContentResolver.java:2318)
W MediaStore: at android.provider.MediaStore$Images$Media.insertImage(MediaStore.java:2097)
W MediaStore: at android.provider.MediaStore$Images$Media.insertImage(MediaStore.java:2059)
2.问题分析
显然这个异常并不是我们 App 中定义的,从日志可以看到程序执行到 MediaStore.Images.Media.insertImage() 方法出现异常了,异常是 MediaProvider.ensureFileColumns 抛出的,关键字是 Failed to build unique file 。
那只能查找源码了。在源码中搜 MediaProvider 的 ensureFileColumns 方法中,的确看到抛出了上述异常。

可以看到,这个一样应该是 FileUtils.buildUniqueFile() 或者 FileUtils.buidlNonUniqueFile() 方法抛出的。查看源码,我们发现是在 FileUtils.buildUniqueFile() 调用 FileUtils.buildUniqueFileWithExtension() 方法,抛出了异常。

看下这个方法大致就可以明白,同一名称的文件会被系统在默认添加(1...)等数字用以标识,例如我有一个aa.txt文件,当我要再次生成aa.txt时,系统会帮我生成aa (1).txt文件,再生成则是aa (2).txt。当括号中的名称数量大于32(含32,也就是说同一文件名的数量超过33个时)后就抛异常。
至此,破案了。
我们在调用
MediaStore.Images.Media.insertImage(getContentResolver(), photoPath, null, null);
方法时,第三个参数,插入数据库的文件的名称,传的 null, 系统会默认生成一个文件名,Image.jpg, 再次插入的则为 Image(1).jpg...
3.修改方案
修改方案明了了,只需要再插入系统数据库时,指定文件名。并且要尽量保持唯一。看来,系统接口设计很严谨,接口中每一个参数都是有意义的,比如该第四个参数,description,文件的描述,最好也要赋值。
记一个 Andorid 生成文件失败的bug的更多相关文章
- Python 写了一个批量生成文件夹和批量重命名的工具
Python 写了一个批量生成文件夹和批量重命名的工具 目录 Python 写了一个批量生成文件夹和批量重命名的工具 演示 功能 1. 可以读取excel内容,使用excel单元格内容进行新建文件夹, ...
- 记PHP下载大文件失败的一次坑
说明 php提供文件的储存和下载,nginx作为web服务器,fpm做解析. 现象 当下载一个5M大小的图片时,总提示下载失败,或下载下来的文件不完整,仅显示部分图像(每次下载不一样) php下载相关 ...
- springboot项目下载文件功能中-切面-导致的下载文件失败的bug
背景:使用spring提供的 ResponseEntity 和Resource结合,实现的下载文件功能 bug:Resource已经加载到了文件, 并且通过 ResponseEntity 构建了响应, ...
- 记一个SwipeMenuListView侧滑删除错乱的Bug
做侧滑删除网上有很多方案,比如重写Listview实现滑动的监听,今天说下一个SwipeListView,这个是之前一个朋友在网上开源的一个封装组件,能够适用于多种情况,项目地址:https://gi ...
- 记一个全局变量"冒充"局部变量引起的bug
看代码相当简单直观,觉得怎么都不会出错,可运行结果明明就是错了 - 对着vim摸着脑袋就是想不出哪里有问题,可去掉新加的代码,就又可以了. 没办法,只好祭出杀手锏:一行一行注释掉来观察... 反映问题 ...
- CSVWriter生成文件时writer.writeRecord();方法保存的文件末尾多一个空行
一.问题,CSVWriter生成文件时使用writer.writeRecord();方法保存的文件末尾多一个空行,效果图如下: 目标结果:(去掉末尾空行) 二.关键代码如下(修改前代码): /** * ...
- 记-ItextPDF+freemaker 生成PDF文件---导致服务宕机
摘要:已经上线的项目,出现服务挂掉的情况. 介绍:该服务是专门做打印的,业务需求是生成PDF文件进行页面预览,主要是使用ItextPDF+freemaker技术生成一系列PDF文件,其中生成流程有:解 ...
- 记Windows的一个存在了十多年的bug
bug Windows有一个bug,持续了十多年,从Windows Visita开始(2007年),一直存在,直到Windows11(2021年)才修复(其实也不叫修复,后面我再具体说),而Windo ...
- 写入数据到Plist文件中时,第一次要创建一个空的数组,否则写入文件失败
#pragma mark - 保存数据到本地Plist文件中 - (void)saveValidateCountWithDate:(NSString *)date count:(NSString *) ...
- Log4j使用笔记:每天生成一个日志文件、按日志大小生成文件
其中TestLog4j.java如下: package cn.zhoucy.test; import org.apache.log4j.Logger; public class TestLog4j { ...
随机推荐
- awk的简单样例
shell awk求和 当第一列相同时,对应的第二列相加 awk'{sum[$1]+=$2}END{for(c in sum){print c,sum[c]}}'输入文件名 在Shell中,我们可以用 ...
- 使用smem 计算Oracle用户下内存占用情况.
1. 本来计划使用 ps 命令进行查看, 但是发现ps 最多查询出来的是 RSS的内存数据, 会多添加很多冗余的内存数据量进来, 于是作罢 2. 找了下公司的方神, 说可以使用smem 然后简单看了下 ...
- NOI2023 游记
不完全按时间顺序写.记录 NOI 的一些琐事. 从 XDFZ 坐大巴 5 个小时来到成七.第一眼看到的是一个放着 NOI 牌子的台阶,还有一个签名墙.好像在我们之前到的人不太多? 用中英双语签名(冷月 ...
- 【发现一个小问题】坑爹的官方日志库`golang.org/x/exp/slog`,凭啥不让我设置debug级别日志
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 一个代码使用了官方的日志库"golang.org ...
- 总结一个问题:csdn发布文章页面为空或者创作内容管理为空
总结一个问题:csdn发布文章页面或者创作内容管理为空 解决方案: 打开chrome浏览器的设置: 点击清除数据: 选择高级里清除数据,一般24小时就可以了,不行就7天
- 6.8 Windows驱动开发:内核枚举Registry注册表回调
在笔者上一篇文章<内核枚举LoadImage映像回调>中LyShark教大家实现了枚举系统回调中的LoadImage通知消息,本章将实现对Registry注册表通知消息的枚举,与LoadI ...
- SpringCloud-07-Hystrix
Hystrix 熔断器 1.Hystrix 概述 Hystix 是 Netflix 开源的一个延迟和容错库,用于隔离访问远程服务.第三方库,防止出现级联失败(雪崩). 雪崩:一个服务失败,导致整条链路 ...
- 小型命令解析器|minShell|多进程|重定向|进程控制【超详细的代码注释和解释】
前言 那么这里博主先安利一下一些干货满满的专栏啦! 手撕数据结构https://blog.csdn.net/yu_cblog/category_11490888.html?spm=1001.2014. ...
- PHP常用类
PHP常用类 一.分页类 <?php /** * 分页类 * 调用方式: * $p=new Page(总条数,显示页码链接数量,当前页码,每页显示条数,[链接]); * print_r($p-& ...
- ABC 333
ABCDE 赛时 AC. F 列方程:\(f_{i,j}\) 表示有 \(i\) 个人,第 \(j\) 个人最终活下来的概率. \(f_{i,1}=\dfrac{1}{2}f_{i,i}\),因为只有 ...