鸿蒙专家 发表于 2026-9-1 16:00:00

鸿蒙React Native文件处理三件套实战与避坑

在鸿蒙上做 React Native(RNOH)开发,遇到从相册选图、压缩后上传这类需求时,很容易卡在“拿到 URI 之后怎么读文件内容”这一步。浏览器里有 File、Blob、FileReader 三件套,而 React Native 从 0.72 左右开始补齐这些 Web 标准 API,到 0.82 已经和浏览器实现基本对齐。也就是说,在浏览器里怎么写文件处理,在鸿蒙上的 RN 里就可以怎么写,File、Blob、FileReader 都是全局可用的。

这三者的关系是一条文件处理链路:Blob 是原始二进制数据的容器,有 size、type 属性,支持 slice 切片;File 继承 Blob,额外带 name 和 lastModified,代表一个具体文件;FileReader 负责异步读取 Blob/File,支持读为文本、DataURL、ArrayBuffer。在 JS 层可以直接确认它们是否可用:


console.log(typeof File); // 'function'
console.log(typeof Blob); // 'function'
console.log(typeof FileReader); // 'function'


先看 Blob。可以从字符串、ArrayBuffer、其他 Blob 组合创建,也可以对已有 Blob 做切片。比如:


const blob = new Blob(['Hello, 鸿蒙 React Native!'], { type: 'text/plain' });
console.log(blob.size); // 字符串字节数
console.log(blob.type); // 'text/plain'

const sliced = blob.slice(0, 5); // 前 5 个字节,这里的字符是 ASCII,所以得到 'Hello'


File 的构造方式类似 Blob,只是多了文件名和最后修改时间:


const file = new File(, 'hello.txt', { type: 'text/plain', lastModified: Date.now() });
console.log(file.name); // 'hello.txt'
console.log(file instanceof Blob); // true


如果是从网络获取文件,fetch 响应没有直接的 file() 方法,但可以先用 blob() 拿到 Blob,再包一层 File:


const response = await fetch('https://example.com/data.json');
const blob = await response.blob();
const file = new File(, 'data.json', { type: blob.type });


FileReader 的用法和浏览器一致,注意要同时处理 onload 和 onerror,否则读取失败时很难排查:


const readFileAsText = (file) => {
return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = () => reject(reader.error);
    reader.readAsText(file);
});
};


实战中常用几个场景:一是文本文件读写,创建 Blob/File 后用 FileReader 读回字符串;二是大文件切片上传,用 file.slice 按固定大小切块,配合 FormData 逐块提交;三是日志合并,把多段 Blob 拼成一个新 Blob 再导出;四是 JSON 数据导出,用 JSON.stringify 生成字符串再包成 Blob。这些场景代码逻辑不复杂,但注意 Blob 和 File 都是 JS 内存对象,不是磁盘上的真实文件。

除了 API 用法,鸿蒙上更值得关注的是几个坑。

第一个坑:File 不能直接从 URI 创建。很多人会写成 new File(, 'photo.jpg'),这不会报错,但文件内容完全不对。正确做法是先 fetch(uri) 拿到响应,再转成 Blob 和 File。

第二个坑:大 Blob 会占满 JS 内存。几百 MB 的 Blob 全部存在 JS 堆里,很容易 OOM。建议限制单文件大小,大文件务必走切片。

第三个坑:FileReader 的 abort() 并不完全“干净”。调用 abort() 后仍然会触发 onloadend,所以要在 onabort 里单独做状态清理,不能把 onloadend 当成正常完成。

第四个坑:onprogress 事件不可靠。在 RNOH 中,onprogress 并非所有场景都会触发,别用它做上传进度条,否则进度会卡住。可以用分片计数等方式自己估算进度。

第五个坑:Blob.slice 负值偏移的行为可能与浏览器不完全一致。为了兼容性,slice 的 start 和 end 都用非负整数,不要依赖负数倒数的特性。

最后做个总结:File、Blob、FileReader 是纯 JS 层能力,不依赖原生桥接,和 TTSModule、OCRModule 这类 TurboModule 不同,不需要 C++ 映射,也不需要 ArkTS 实现。但正因为如此,它们和“从设备读取真实文件”是两回事。小文件直接 readAsText,大文件用 slice 分片,始终处理 onerror,Blob.type 尽量写明 MIME 类型,配合 TextEncoder/TextDecoder 处理编码,基本就能在鸿蒙上顺畅完成文件处理了。

热心网友7 发表于 2026-9-1 19:00:00

Re: 鸿蒙React Native文件处理三件套实战与避坑

干货很足。之前我在鸿蒙上处理文件也踩过“File 不能直接拿 URI 创建”的坑,照着浏览器习惯写结果内容全不对。Blob 和 File 的内存占用问题确实得重视,几百兆直接撑爆 JS 堆,最后只能老老实实分片。另外 onprogress 不可靠这点很关键,省得白写进度条。总结得清晰,收藏了。

热心网友6 发表于 2026-9-1 19:05:00

Re: 鸿蒙React Native文件处理三件套实战与避坑

楼主的实战总结很到位,尤其是“File 不能直接从 URI 创建”这个坑,我刚接触的时候也踩过,以为 new File 就能拿到内容,结果读出来全是空。后来也是先 fetch 再转 Blob 才解决。另外大文件内存问题确实要重视,我这边用 slice 分片后,上传大视频基本稳了。感谢楼主把 FileReader 的 abort 行为和 onprogress 不可靠也点出来了,这两个细节不注意真的容易出诡异 bug。

热心网友3 发表于 2026-9-1 19:10:00

Re: 鸿蒙React Native文件处理三件套实战与避坑

楼主的分享很实在,尤其是几个坑点,正好是我之前踩过的。之前我在鸿蒙上做类似需求时,也是纠结“URI怎么转成File”,后来发现fetch(uri)那一步确实绕不开,直接new File确实拿不到内容,这个坑太典型了。 还有大文件内存问题,我们当时为了省事直接把整个视频读成Blob,结果在低端机上直接OOM,后来老老实实切片上传,果然稳多了。onprogress那个坑也遇到过,本来想做个进度条,结果半天不动,最后也是自己按分片数算的进度。 FileReader的abort()那块,我之前没注意onloadend还会触发,差点把清理逻辑写错地方,还好本地测出问题来了。楼主总结得很到位,小文件直接读,大文件分片,MIME类型写清楚,基本就够用了。感谢分享,收藏了!
页: [1]
查看完整版本: 鸿蒙React Native文件处理三件套实战与避坑