查看: 78|回复: 0

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

[复制链接]
发表于 21 分钟前 | 显示全部楼层 |阅读模式
在鸿蒙上做 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 层可以直接确认它们是否可用:
  1. console.log(typeof File); // 'function'
  2. console.log(typeof Blob); // 'function'
  3. console.log(typeof FileReader); // 'function'
复制代码

先看 Blob。可以从字符串、ArrayBuffer、其他 Blob 组合创建,也可以对已有 Blob 做切片。比如:
  1. const blob = new Blob(['Hello, 鸿蒙 React Native!'], { type: 'text/plain' });
  2. console.log(blob.size); // 字符串字节数
  3. console.log(blob.type); // 'text/plain'
  4. const sliced = blob.slice(0, 5); // 前 5 个字节,这里的字符是 ASCII,所以得到 'Hello'
复制代码

File 的构造方式类似 Blob,只是多了文件名和最后修改时间:
  1. const file = new File([blob], 'hello.txt', { type: 'text/plain', lastModified: Date.now() });
  2. console.log(file.name); // 'hello.txt'
  3. console.log(file instanceof Blob); // true
复制代码

如果是从网络获取文件,fetch 响应没有直接的 file() 方法,但可以先用 blob() 拿到 Blob,再包一层 File:
  1. const response = await fetch('https://example.com/data.json');
  2. const blob = await response.blob();
  3. const file = new File([blob], 'data.json', { type: blob.type });
复制代码

FileReader 的用法和浏览器一致,注意要同时处理 onload 和 onerror,否则读取失败时很难排查:
  1. const readFileAsText = (file) => {
  2.   return new Promise((resolve, reject) => {
  3.     const reader = new FileReader();
  4.     reader.onload = () => resolve(reader.result);
  5.     reader.onerror = () => reject(reader.error);
  6.     reader.readAsText(file);
  7.   });
  8. };
复制代码

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

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

第一个坑:File 不能直接从 URI 创建。很多人会写成 new File([uri], '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 处理编码,基本就能在鸿蒙上顺畅完成文件处理了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-1 16:21 , Processed in 0.021732 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部