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

ContentResolver返回文件大小异常求助(Android Oreo模拟器)

这个问题我之前也碰到过,本质是Android 8.0(API 26)开始系统相机对MediaStore字段的写入逻辑变了,具体原因和解决方案如下:

问题原因

  • MediaStore.SIZE字段的统计逻辑变更:在API 25及以前,MediaStore的MediaColumns.SIZE存储的是文件在磁盘上的实际总大小;但从API 26开始,系统相机应用在将拍摄的图片插入MediaStore时,填入的SIZE值仅对应图片的像素主体数据大小(比如JPEG文件中去除了EXIF元数据、内置缩略图APP段等额外内容后的大小),而非整个文件的实际字节数。
  • adb和文件详情的统计方式:adb ls -al和文件详情显示的是文件在存储系统中的完整大小,包含了所有附加数据(EXIF信息、JPEG缩略图块等),所以数值更大。
  • Document API的一致性:系统提供的DocumentProvider对于媒体文件,直接复用了MediaStore中的SIZE字段值,所以返回的大小和ContentResolver查询结果一致。

解决方案

不要依赖MediaColumns.SIZE字段获取准确的文件大小,而是通过ContentResolver.openFileDescriptor()获取文件的实际统计大小,这个方法会直接读取文件系统的真实数据:

private fun getActualFileSize(contentResolver: ContentResolver, fileUri: Uri): Long {
    return try {
        contentResolver.openFileDescriptor(fileUri, "r")?.use { fileDescriptor ->
            fileDescriptor.statSize
        } ?: 0L
    } catch (e: IOException) {
        // 处理异常,比如权限问题或文件不存在
        0L
    }
}

这个方法获取的statSize是文件在磁盘上的真实字节数,和adb ls显示的结果一致。

如果你需要同时获取文件名和大小,可以结合原来的查询逻辑和这个方法:

private fun getFileInfo(contentResolver: ContentResolver, fileUri: Uri): Pair<String, Long>? {
    val projection = arrayOf(MediaStore.MediaColumns.DISPLAY_NAME)
    val metaCursor = contentResolver.query(fileUri, projection, null, null, null)
    metaCursor?.use {
        if (it.moveToFirst()) {
            val displayName = it.getString(it.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME))
            val actualSize = getActualFileSize(contentResolver, fileUri)
            return Pair(displayName, actualSize)
        }
    }
    return null
}

额外验证

你可以用exiftool查看这张图片的结构,会发现:

  • 图片的JPEG主体数据大小约为29kb
  • 加上EXIF元数据、内置缩略图等附加内容后,总大小正好是44/45kb,这和你看到的数值完全对应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:28:55