我们做的是一个企业内部的文档审批系统。用户在手机上下载了 50 页的 PDF 审批单,然后想直接流转到平板上用大看。
鸿蒙的分布式能力听起来很牛,我直接用了底层的 @ohos.file.fs 配合分布式软总线来传。本地局域网测试,10MB 文件秒传。结果带去给客户演示,网络稍微差一点,应用直接闪退,文件传到一半变成了 0 字节。
这篇记录我是怎么踩坑,最后转向系统级"分布式文件系统"的血泪史。
直接用 fs 拷贝
我最初的做法极其头铁:获取源文件的 fd(文件描述符),利用分布式网络建立 Socket 连接,硬生生地读流、发流、写流。
typescript
// 伪代码:极其痛苦的内存读写
const file = fs.openSync(srcPath, fs.OpenMode.READ_ONLY);
const buffer = new ArrayBuffer(4096);
let readLen = fs.readSync(file.fd, buffer);
while (readLen > 0) {
// 通过网络发出去
await socket.send(buffer);
readLen = fs.readSync(file.fd, buffer);
}
断点续传的噩梦。 只要网络抖动一下,Socket 断开,整个文件就废了。而且没有进度回调,UI 上只能一直转圈。
坑点二:内存溢出。 如果文件大一点,为了追求速度,我把 Buffer 开到几兆,几轮下来,GC 根本来不及回收,直接 OOM。
转变思路使用 @ohos.file.distributedFile
后来我去翻了 HarmonyOS 的分布式特性文档,发现系统早就封装好了分布式文件系统,直接提供了跨设备文件访问的能力。
不需要你写 Socket,不需要你处理流,像操作本地文件一样操作远程文件。
首先,获取可信设备的 NetworkID:
typescript
import deviceManager from '@ohos.distributedDeviceManager';
const dm = deviceManager.createDeviceManager('com.example.docapp');
const devices = dm.getTrustedDeviceListSync();
const remoteDevice = devices[0]; // 假设取第一台平板
然后,直接用系统 API 发起拷贝。这玩意儿底层自带断点续传和加密:
typescript
import fs from '@ohos.file.fs';
async function transferFileToTablet(localPath: string, remoteDeviceId: string) {
try {
// 打开远端设备的沙箱目录
const remoteDir = await fs.open(remoteDeviceId, '/data/storage/el2/base/files/', fs.OpenMode.READ_WRITE);
// 直接把本地文件拷贝过去
await fs.copyFile(localPath, remoteDir.fd);
console.info('文件流转成功');
} catch (err) {
console.error('流转失败', err);
} finally {
fs.closeSync(remoteDir);
}
}
权限与生命周期
虽然 API 极度简单,但这里有一个极其恶心的限制:文件流转必须在应用处于前台时进行,且需要用户授权。
如果用户切到了后台,或者锁屏了,底层为了安全会直接切断文件描述符。
怎么解决体验问题?
如果你要传大文件,千万别傻等着。必须结合后台长时任务(backgroundTaskManager)和系统通知栏。在传输开始前,申请一个"数据传输"长时任务,这样即使锁屏,也能安安稳稳传完。
-
放弃自己造轮子 ,直接拥抱
@ohos.file.distributedFile,稳定性天差地别。 -
传输大文件必须加长时任务,否则切个后台教你做人。
-
远端路径必须严格校验,防止路径穿越漏洞。