本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

  • 分布式文件系统为应用提供跨设备文件拷贝的能力

  • 可以通过基础文件接口进行跨设备拷贝文件

应用场景

多设备数据流转

  • 设备组网互联之后,设备A上的应用可将沙箱文件拷贝到设备A的分布式目录

  • 设备B在粘贴时,从B设备的分布式目录下将文件拷贝到对应的沙箱文件中

二、开发步骤

2.1 步骤一:完成分布式组网

  • 两个设备登录同一账号

  • 保证设备蓝牙和Wi-Fi功能开启

  • 蓝牙无需互连

  • Wi-Fi无需接入同一个局域网

2.2 步骤二:授权分布式数据同步权限

  • 权限名称:ohos.permission.DISTRIBUTED_DATASYNC

  • 授权方式:user_grant(需要用户动态授权)

  • 申请方式:调用requestPermissionsFromUser接口

  • 交互形式:动态弹窗方式向用户申请授权

代码实现

import { common, abilityAccessCtrl } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

let atManager = abilityAccessCtrl.createAtManager();

try {
  // 以动态弹窗的方式向用户申请授权
  atManager.requestPermissionsFromUser(context, ['ohos.permission.DISTRIBUTED_DATASYNC'])
    .then((result) => {
      console.info(`request permission result: ${JSON.stringify(result)}`);
    }).catch((err: BusinessError) => {
      console.error(`Failed to request permissions from user. Code: ${err.code}, message: ${err.message}`);
    });
} catch (error) {
  let err: BusinessError = error as BusinessError;
  console.error(`Catch err. Failed to request permissions from user. Code: ${err.code}, message: ${err.message}`);
}

2.3 步骤三:执行跨设备文件拷贝

核心机制

  • 同一应用在不同设备之间实现跨设备文件拷贝

  • 只需要将对应的文件放在应用沙箱的分布式目录即可

2.3.1 设备A:将待拷贝沙箱文件拷贝到分布式目录

文件路径说明

  • context.filesDir:应用沙箱目录

  • context.distributedFilesDir:应用分布式目录

代码实现

import { fileIo as fs } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { fileUri } from '@kit.CoreFileKit';

let pathDir: string = context.filesDir;
let distributedPathDir: string = context.distributedFilesDir;

// 待拷贝文件沙箱路径
let filePath: string = pathDir + '/src.txt';

try {
  // 准备待拷贝沙箱文件
  let file = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
  fs.writeSync(file.fd, 'Create file success');
  fs.closeSync(file);
} catch (error) {
  console.error(`Failed to createFile. Code: ${error.code}, message: ${error.message}`);
}

// 获取待拷贝源文件uri
let srcUri = fileUri.getUriFromPath(filePath);

// 获取目标路径(分布式目录)的uri
let destUri: string = fileUri.getUriFromPath(distributedPathDir + '/src.txt');

try {
  // 将沙箱路径下的源文件拷贝到目标分布式目录下
  fs.copy(srcUri, destUri).then(() => {
    console.info(`Succeeded in copying---. `);
    console.info(`src: ${srcUri} dest: ${destUri}`);
  }).catch((error: BusinessError) => {
    let err: BusinessError = error as BusinessError;
    console.error(`Failed to copy. Code: ${err.code}, message: ${err.message}`);
  });
} catch (error) {
  console.error(`Catch err. Failed to copy. Code: ${error.code}, message: ${error.message}`);
}
2.3.2 设备B:从分布式目录拷贝文件到沙箱

流程

  1. 获取设备A的networkId

  2. 连接分布式文件系统

  3. 从分布式目录拷贝文件

  4. 清理分布式目录下的临时文件

代码实现

import { fileIo as fs } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { fileUri } from '@kit.CoreFileKit';
import { distributedDeviceManager } from '@kit.DistributedServiceKit';

// ...
let pathDir: string = context.filesDir;
let distributedPathDir: string = context.distributedFilesDir;

// 待拷贝文件的目标路径(沙箱路径)
let destPath: string = pathDir + '/dest.txt';

// 获取目标路径uri
let destUri = fileUri.getUriFromPath(destPath);

// 拷贝源文件路径(分布式目录)
let srcPath = distributedPathDir + '/src.txt';

// 获取源路径uri
let srcUri: string = fileUri.getUriFromPath(srcPath);

// 定义拷贝回调
let progressListener: fs.ProgressListener = (progress: fs.Progress) => {
  console.info(`progressSize: ${progress.processedSize}, totalSize: ${progress.totalSize}`);
};

let options: fs.CopyOptions = {
  'progressListener': progressListener
};

// 通过分布式设备管理的接口获取设备A的networkId信息
let dmInstance = distributedDeviceManager.createDeviceManager('com.example.hap');
let deviceInfoList: distributedDeviceManager.DeviceBasicInfo[] = dmInstance.getAvailableDeviceListSync();

if (deviceInfoList && deviceInfoList.length > 0) {
  console.info(`success to get available device list`);
  // 这里只是两个设备连接,列表中首个即为A设备的networkId
  let networkId = deviceInfoList[0].networkId;
  
  // 定义访问分布式目录的回调
  let listeners: fs.DfsListeners = {
    onStatus: (networkId: string, status: number): void => {
      console.error(`Failed to access public directory,${status}`);
    }
  };
  
  // 开始跨设备文件拷贝
  fs.connectDfs(networkId, listeners).then(() => {
    try {
      // 将分布式目录下的文件拷贝到其他沙箱路径下
      fs.copy(srcUri, destUri, options).then(() => {
        console.info(`Succeeded in copying from distribted path`);
        console.info(`src: ${srcUri} dest: ${destUri}`);
        // 拷贝完成后清理分布式目录下的临时文件
        fs.unlinkSync(srcPath);
      }).catch((error: BusinessError) => {
        let err: BusinessError = error as BusinessError;
        console.error(`Failed to copy. Code: ${err.code}, message: ${err.message}`);
      });
    } catch (error) {
      console.error(`Catch err. Failed to copy. Code: ${error.code}, message: ${error.message}`);
    }
  }).catch((error: BusinessError) => {
    let err: BusinessError = error as BusinessError;
    console.error(`Failed to connect dfs. Code: ${err.code}, message: ${err.message}`);
  });
}

2.4 步骤四:断开链路

跨设备文件拷贝完成后,需要断开分布式文件系统连接

代码实现

import { BusinessError } from '@kit.BasicServicesKit';
import { distributedDeviceManager } from '@kit.DistributedServiceKit';
import { fileIo as fs } from '@kit.CoreFileKit';

// 获取设备A的networkId
// ...
let dmInstance = distributedDeviceManager.createDeviceManager('com.example.hap');
let deviceInfoList: distributedDeviceManager.DeviceBasicInfo[] = dmInstance.getAvailableDeviceListSync();

if (deviceInfoList && deviceInfoList.length > 0) {
  console.info(`Success to get available device list`);
  let networkId = deviceInfoList[0].networkId;
  
  // 关闭跨设备文件访问
  fs.disconnectDfs(networkId).then(() => {
    console.info(`Success to disconnect dfs`);
  }).catch((err: BusinessError) => {
    console.error(`Failed to disconnect dfs. Code: ${err.code}, message: ${err.message}`);
  });
}

三、相关API总结

3.1 权限申请相关

API 功能 所属模块
abilityAccessCtrl.createAtManager() 创建访问控制管理器 @kit.AbilityKit
requestPermissionsFromUser() 动态申请用户权限 @kit.AbilityKit

3.2 文件操作相关

API 功能 所属模块
fs.openSync() 打开文件 @kit.CoreFileKit
fs.writeSync() 写入文件 @kit.CoreFileKit
fs.closeSync() 关闭文件 @kit.CoreFileKit
fs.copy() 拷贝文件 @kit.CoreFileKit
fs.unlinkSync() 删除文件 @kit.CoreFileKit

3.3 分布式文件系统相关

API 功能 所属模块
context.distributedFilesDir 获取分布式目录路径 @kit.AbilityKit
fileUri.getUriFromPath() 从路径获取URI @kit.CoreFileKit
fs.connectDfs() 连接分布式文件系统 @kit.CoreFileKit
fs.disconnectDfs() 断开分布式文件系统 @kit.CoreFileKit
fs.DfsListeners 分布式文件访问状态监听 @kit.CoreFileKit
fs.ProgressListener 拷贝进度监听 @kit.CoreFileKit
fs.CopyOptions 拷贝选项配置 @kit.CoreFileKit

3.4 设备管理相关

API 功能 所属模块
distributedDeviceManager.createDeviceManager() 创建设备管理器 @kit.DistributedServiceKit
getAvailableDeviceListSync() 同步获取可用设备列表 @kit.DistributedServiceKit
DeviceBasicInfo.networkId 设备网络ID @kit.DistributedServiceKit

四、完整流程

设备A                             设备B
  |                                |
  |-- 1. 创建沙箱文件             |
  |-- 2. 拷贝到分布式目录         |
  |     (fs.copy)                 |
  |                                |
  |                                |-- 3. 获取设备A的networkId
  |                                |    (getAvailableDeviceListSync)
  |                                |
  |                                |-- 4. 连接分布式文件系统
  |                                |    (fs.connectDfs)
  |                                |
  |                                |-- 5. 从分布式目录拷贝文件
  |                                |    (fs.copy + ProgressListener)
  |                                |
  |                                |-- 6. 清理分布式目录临时文件
  |                                |    (fs.unlinkSync)
  |                                |
  |                                |-- 7. 断开分布式文件系统连接
  |                                |    (fs.disconnectDfs)

五、注意事项

5.1 组网

  • 两个设备必须登录同一华为账号

  • 蓝牙和Wi-Fi功能必须开启

  • 蓝牙不需要互连

  • Wi-Fi不需要接入同一个局域网

5.2 权限

  • 必须动态申请ohos.permission.DISTRIBUTED_DATASYNC权限

  • 权限类型为user_grant,需要用户通过弹窗授权

  • 未授权时无法进行跨设备文件操作

5.3 目录说明

  • 分布式目录context.distributedFilesDir,跨设备文件共享的中转目录

  • 沙箱目录context.filesDir,应用私有文件目录

  • 跨设备文件拷贝必须通过分布式目录进行中转

5.4 操作规范

  1. 设备A:将沙箱文件拷贝到本机分布式目录

  2. 设备B:从本机分布式目录拷贝文件到沙箱目录

  3. 临时文件清理:拷贝完成后需要清理分布式目录下的临时文件(fs.unlinkSync

  4. 连接管理:跨设备操作前需要connectDfs,操作完成后需要disconnectDfs

本质

  1. 不是直接设备到设备的拷贝

  2. 而是通过各自设备的分布式目录作为中转

  3. 设备A:沙箱 → 分布式目录(本地操作)

  4. 设备B:分布式目录 → 沙箱(本地操作)

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐