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

RNFetchBlobStat获取图片大小与设备显示不一致问题及修复

设备显示照片大小与RNFetchBlob/ImagePicker获取值不一致的问题解析及修复

问题场景

我在React Native项目中实现了文件选择大小限制:照片超过10MB或视频超过100MB时禁止上传,使用RNFetchBlob.fs.stat获取文件大小,同时发现ImagePicker返回的fileSize结果和stat一致。但遇到一个问题:设备相册显示某照片大小为1.42MB,而代码返回的是3466195字节(约3.31MB),两者存在明显差异。相关核心代码如下:

const MAX_SIZE_PHOTO = 10485760 //10*1024*1024 
const MAX_SIZE_VIDEO = 104857600//100*1024*1024 

getSizeImg = (type, source) => { 
  RNFetchBlob.fs.stat(source.uri.replace('file:///', '').replace('file://', '').replace('file:/', '')) 
    .then((stats) => { 
      console.log("file size", stats.size) 
      if (type === 'video') { 
        if (stats.size > MAX_SIZE_VIDEO) { 
          Alert.alert(null, "This video is too large to be uploaded") 
          error() 
          return 
        } 
        uploadVideo(source, completeHandler, progressHandler, error, diary_id, token) 
      } else { 
        if (stats.size > MAX_SIZE_PHOTO) { 
          Alert.alert(null, "This image is too large to be uploaded") 
          error() 
          return 
        } 
        uploadImage(source) 
      } 
    }) 
    .catch((err) => { 
      console.log("getSize", err) 
      error(err) 
    }) 
} 

// 图片选择和视频选择函数省略...

差异产生的核心原因

  • 设备显示的是优化后的预览文件大小:绝大多数设备的相册会对拍摄的原始照片进行优化处理——比如生成低分辨率的缩略图用于快速预览,或者在开启云存储优化(如iCloud照片库、Google照片的“高质量存储”)时,设备本地仅保存压缩后的小尺寸文件,原始高分辨率文件存储在云端。你在设备上看到的1.42MB就是这个预览/优化后的文件大小,而RNFetchBlob和ImagePicker获取的是原始文件的真实大小。
  • URI处理逻辑不严谨:代码中手动替换file://系列前缀的方式没有适配跨平台的URI格式差异。比如iOS上ImagePicker返回的uri可能是ph://格式的资源URI,直接替换前缀无法正确映射到设备显示的预览文件路径,导致读取到的是原始高分辨率文件而非预览图。

修复方案

方案1:正确处理跨平台URI,确保读取目标文件

放弃手动替换URI前缀的方式,使用RNFetchBlob提供的wrap方法统一处理iOS/Android的资源URI,这能确保你访问到的是用户在相册中看到的对应文件:

getSizeImg = (type, source) => {
  // 使用RNFetchBlob.wrap适配跨平台URI
  const targetFilePath = RNFetchBlob.wrap(source.uri);
  RNFetchBlob.fs.stat(targetFilePath)
    .then((stats) => {
      console.log("匹配设备显示的文件大小", stats.size);
      // 后续大小判断逻辑不变
      if (type === 'video') {
        if (stats.size > MAX_SIZE_VIDEO) {
          Alert.alert(null, "This video is too large to be uploaded")
          error()
          return
        }
        uploadVideo(source, completeHandler, progressHandler, error, diary_id, token)
      } else {
        if (stats.size > MAX_SIZE_PHOTO) {
          Alert.alert(null, "This image is too large to be uploaded")
          error()
          return
        }
        uploadImage(source)
      }
    })
    .catch((err) => {
      console.log("getSize", err)
      error(err)
    })
}

方案2:压缩图片后再判断大小(对齐设备显示)

如果希望APP内的大小判断逻辑完全和设备显示的一致,可以先对选中的图片进行压缩,再基于压缩后的文件大小做限制:

  1. 安装图片压缩库:
npm install react-native-image-resizer --save
# 或使用yarn
yarn add react-native-image-resizer
  1. 修改getSizeImg方法,加入压缩逻辑:
import ImageResizer from 'react-native-image-resizer';

getSizeImg = (type, source) => {
  if (type === 'image') {
    // 压缩图片到设备预览级别的尺寸和质量
    ImageResizer.createResizedImage(
      source.uri,
      1920, // 目标宽度,可根据需求调整
      1080, // 目标高度,可根据需求调整
      'JPEG',
      80 // 压缩质量(0-100,数值越高质量越好)
    ).then((resizedImage) => {
      // 获取压缩后的文件大小
      RNFetchBlob.fs.stat(RNFetchBlob.wrap(resizedImage.uri))
        .then((stats) => {
          console.log("压缩后文件大小", stats.size);
          if (stats.size > MAX_SIZE_PHOTO) {
            Alert.alert(null, "This image is too large to be uploaded")
            error()
            return
          }
          // 使用压缩后的图片进行上传
          uploadImage({
            uri: resizedImage.uri,
            name: source.name,
            type: source.type
          })
        })
    }).catch((err) => {
      console.log("图片压缩失败", err);
      error(err);
    });
  } else {
    // 视频处理逻辑使用wrap适配URI
    const targetFilePath = RNFetchBlob.wrap(source.uri);
    RNFetchBlob.fs.stat(targetFilePath)
      .then((stats) => {
        console.log("视频文件大小", stats.size);
        if (stats.size > MAX_SIZE_VIDEO) {
          Alert.alert(null, "This video is too large to be uploaded")
          error()
          return
        }
        uploadVideo(source, completeHandler, progressHandler, error, diary_id, token)
      })
      .catch((err) => {
        console.log("getSize", err)
        error(err)
      })
  }
}

方案3:明确告知用户差异(最简单的方案)

如果不需要对齐设备显示大小,只需修改提示文本,明确说明是原始文件大小超过限制,避免用户困惑:

Alert.alert(null, `This original image is too large to be uploaded (current size: ~${(stats.size/1024/1024).toFixed(2)}MB)`)

内容的提问来源于stack exchange,提问作者Trần Hòa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:19:26