本地文件传给平板直接卡死?HarmonyOS 7 分布式文件传输实录

我们做的是一个企业内部的文档审批系统。用户在手机上下载了 50 页的 PDF 审批单,然后想直接流转到平板上用大看。

鸿蒙的分布式能力听起来很牛,我直接用了底层的 @ohos.file.fs 配合分布式软总线来传。本地局域网测试,10MB 文件秒传。结果带去给客户演示,网络稍微差一点,应用直接闪退,文件传到一半变成了 0 字节。

这篇记录我是怎么踩坑,最后转向系统级"分布式文件系统"的血泪史。

https://placeholder-01.jpg/

直接用 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)和系统通知栏。在传输开始前,申请一个"数据传输"长时任务,这样即使锁屏,也能安安稳稳传完。

  1. 放弃自己造轮子 ,直接拥抱 @ohos.file.distributedFile,稳定性天差地别。

  2. 传输大文件必须加长时任务,否则切个后台教你做人。

  3. 远端路径必须严格校验,防止路径穿越漏洞。