鸿蒙开发--FileManagerServiceKit
摘要:HarmonyOS 文件管理服务(File Manager Service Kit)为开发者提供"删除到回收站"功能,避免用户误删文件无法恢复。该服务支持鸿蒙5.0.5+设备,通过调用deleteToTrash接口将文件移至系统回收站而非直接删除。开发时需配置DevEco Studio 5.0.5+环境,核心步骤包括:导入文件管理模块、创建文件选择器、调用删除接口并处理结果。实现流程包含错误
HarmonyOS 文件管理服务:让你的应用支持"删除到回收站"
什么是文件管理服务
你有没有遇到过这种情况:不小心删了一个重要文件,然后就找不回来了?电脑上一般有回收站,删了文件还能从回收站里恢复。但手机上呢?很多手机 App 删除文件就是直接删了,没有后悔的机会。
文件管理服务(File Manager Service Kit)就是来解决这个问题的。它是鸿蒙生态下的文件管理服务,提供了"删除到回收站"的能力。简单说,就是让你的 App 删除文件时,不是直接删掉,而是放到回收站里,用户可以随时恢复。
你可能会问:回收站在哪?在鸿蒙系统里,回收站是系统级的功能,用户可以在文件管理器里找到。你只需要调用文件管理服务的接口,把文件"移到回收站"就行,剩下的事情系统会帮你处理。
核心功能
文件管理服务目前提供的核心功能就一个:
- 删除到回收站:把文件移到回收站,而不是直接删除
虽然功能看起来简单,但这个能力非常重要。想想看,你的 App 如果有文件管理功能,用户肯定会期望有回收站,就像电脑上的回收站一样。没有回收站的文件管理器,用户用起来总是提心吊胆的,生怕一不小心删错了东西。
环境搭建
硬件要求
- 设备类型:华为手机、平板、PC/2in1
- HarmonyOS 系统:HarmonyOS 5.0.5 Release 及以上
软件要求
- DevEco Studio 版本:DevEco Studio 5.0.5 Release 及以上
- HarmonyOS SDK 版本:HarmonyOS 5.0.5 Release SDK 及以上
搭建步骤
- 安装 DevEco Studio:去华为开发者官网下载安装,跟着提示走就行
- 配置开发环境:确保网络环境正常,DevEco Studio 需要联网才能用
- 设备调试:使用真机进行调试,模拟器也可以
项目结构
└── entry/src/main
├── ets
│ ├── entryability
│ │ └── EntryAbility.ets // 程序入口类
│ └── pages
│ └── Index.ets // 主界面
└── resources // 资源文件目录
项目结构非常简单,核心逻辑都在 Index.ets 里。这个 Codelab 的重点就是教你调用文件管理服务的接口,所以代码量不大。
第一步:导入模块
import { fileManagerService } from '@kit.FileManagerServiceKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { picker } from '@kit.CoreFileKit';
import { PromptAction } from '@kit.ArkUI';
导入的模块有点多,一个个来说:
fileManagerService:文件管理服务的核心接口,我们用它来调用"删除到回收站"功能。这是整个文章最重要的模块BusinessError:错误处理用的。华为的 Kit 接口基本都用这个来返回错误信息,包括错误码和错误描述common:获取上下文用的。调用文件管理服务接口时需要传入应用的上下文hilog:日志工具,开发调试的时候看输出用的。出了问题也能查日志,建议别删picker:文件选择器,让用户选择要删除的文件。你想啊,用户得先选中一个文件,才能删除它对吧PromptAction:弹出提示用的,比如"删除成功"、"删除失败"这种提示框
第二步:定义日志标签
const domain = 0x0000;
const tag = 'deleteTag';
定义日志的标签,方便在控制台里找到我们的日志输出。domain 是日志的域,tag 是标签名,你可以随便取,只要方便识别就行。
为什么要定义这个?因为鸿蒙系统里会有很多日志输出,如果你不加标签,根本找不到自己写的日志。就像在一堆信件里找自己的信,有个名字标记就好找多了。
第三步:创建文件选择器
let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
let promptAction: PromptAction = this.getUIContext().getPromptAction();
let selectOptions: picker.DocumentSelectOptions = new picker.DocumentSelectOptions();
selectOptions.defaultFilePathUri = 'file://docs/storage/Users/currentUser';
let documentPicker = new picker.DocumentViewPicker(context);
创建文件选择器的过程,我一行一行解释:
- 获取上下文(context):这是应用的运行环境,很多接口都需要传入这个参数。你可以理解为"当前页面的环境信息"
- 获取提示操作(promptAction):用来弹出提示信息,比如 Toast 提示。不获取这个的话,你就没办法弹提示了
- 创建选择选项(selectOptions):可以设置默认打开的路径。这里设置为用户文件目录,这样用户打开选择器时直接看到的就是自己的文件
- 创建文件选择器(documentPicker):用来让用户选择文件。这个选择器是系统提供的,长得和系统文件管理器一样
defaultFilePathUri 设置了文件选择器打开时默认显示的路径。如果你不设置这个,选择器可能会打开一个默认目录,用户还得自己导航到想要的目录,体验不好。
第四步:选择文件并删除到回收站
documentPicker.select(selectOptions, async (err: BusinessError, documentSelectResult: Array<string>) => {
if (err) {
hilog.error(domain, tag, 'DocumentViewPicker.select failed with err: ' + JSON.stringify(err));
return;
}
// 选择成功,处理文件
});
调用 documentPicker.select 打开文件选择器。用户会看到一个系统文件选择界面,可以选择一个或多个文件。
选择完成后,回调函数会被调用:
- 如果
err有值,说明出了问题(比如用户取消了选择),打印错误信息然后 return - 如果
err没有值,说明选择成功,documentSelectResult里就是用户选中的文件 URI 列表
try {
for (let uri of documentSelectResult) {
hilog.info(domain, tag, 'deleteToTrash start');
const ret: string = await fileManagerService.deleteToTrash(uri);
hilog.info(domain, tag, 'deleteToTrash end, ret:%{public}', ret);
}
promptAction.showToast({
message: `delete success`,
duration: 5
});
} catch (error) {
hilog.error(domain, tag, `error.code: ${error.code}, error.message: ${error.message}`);
promptAction.showToast({
message: `delete failed, error.code: ${error.code}, error.message: ${error.message}`,
duration: 5
});
}
这是核心逻辑,我拆开来说:
- 遍历用户选择的所有文件:用户可能选了多个文件,所以用
for...of循环处理 - 调用
fileManagerService.deleteToTrash(uri):这是整个文章最重要的 API。它不会直接删除文件,而是把文件移到回收站里。用户可以在文件管理器的回收站里找到这些文件,随时恢复 - 全部成功后,弹出"删除成功"的提示:让用户知道操作完成了
- 如果出错了,弹出错误信息:可能是因为文件不存在、权限不足等原因
deleteToTrash 的返回值是一个字符串,表示操作结果。你可以根据这个返回值判断是否成功。
为什么要用 try...catch?因为删除文件可能会失败。比如文件已经被删了、文件路径不对、没有权限等等。如果不捕获异常,程序可能会崩溃。
完整代码
把上面的步骤合在一起,完整的代码是这样的:
import { fileManagerService } from '@kit.FileManagerServiceKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { picker } from '@kit.CoreFileKit';
import { PromptAction } from '@kit.ArkUI';
const domain = 0x0000;
const tag = 'deleteTag';
@Entry
@Component
struct Index {
build() {
Column() {
Button($r('app.string.select_files_to_delete'))
.onClick(async () => {
try {
let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
let promptAction: PromptAction = this.getUIContext().getPromptAction();
let selectOptions: picker.DocumentSelectOptions = new picker.DocumentSelectOptions();
selectOptions.defaultFilePathUri = 'file://docs/storage/Users/currentUser';
let documentPicker = new picker.DocumentViewPicker(context);
documentPicker.select(selectOptions, async (err: BusinessError, documentSelectResult: Array<string>) => {
if (err) {
hilog.error(domain, tag, 'DocumentViewPicker.select failed with err: ' + JSON.stringify(err));
return;
}
try {
for (let uri of documentSelectResult) {
hilog.info(domain, tag, 'deleteToTrash start');
const ret: string = await fileManagerService.deleteToTrash(uri);
hilog.info(domain, tag, 'deleteToTrash end, ret:%{public}', ret);
}
promptAction.showToast({
message: `delete success`,
duration: 5
});
} catch (error) {
hilog.error(domain, tag, `error.code: ${error.code}, error.message: ${error.message}`);
promptAction.showToast({
message: `delete failed, error.code: ${error.code}, error.message: ${error.message}`,
duration: 5
});
}
});
} catch (error) {
let err: BusinessError = error as BusinessError;
hilog.error(domain, tag, 'DocumentViewPicker failed with err: ' + JSON.stringify(err));
}
})
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
}
}
整个流程就是:点击按钮 → 打开文件选择器 → 用户选择文件 → 调用 deleteToTrash 删除到回收站 → 显示结果提示。
看起来代码挺长的,但其实逻辑很简单。大部分代码都是在做准备工作(创建选择器、获取上下文),真正干活的就一行:fileManagerService.deleteToTrash(uri)。
实际应用场景
文件管理服务在实际开发中有很多用途:
文件管理器
// 文件管理器中的删除功能
async function deleteFileToTrash(uri: string) {
try {
const ret: string = await fileManagerService.deleteToTrash(uri);
console.info('文件已移到回收站');
// 可以在这里更新 UI,把文件从列表里移除
} catch (error) {
console.error(`删除失败: ${error.code}, ${error.message}`);
// 提示用户删除失败
}
}
在文件管理器里,用户删除文件时,调用 deleteToTrash 把文件移到回收站,而不是直接删除。这样用户可以随时从回收站恢复文件。
你可能会问:那回收站满了怎么办?鸿蒙系统的回收站有自动清理机制,会按照先进先出的原则清理旧文件。你不需要自己管理回收站的空间。
笔记应用
// 笔记应用中删除附件
async function deleteNoteAttachment(attachmentUri: string) {
try {
await fileManagerService.deleteToTrash(attachmentUri);
// 更新笔记,移除附件引用
console.info('附件已移到回收站');
} catch (error) {
console.error(`删除附件失败: ${error.code}`);
}
}
在笔记应用里,用户删除笔记附件时,也可以用这个功能。附件被移到回收站,用户如果发现误删了,可以去回收站恢复。
图片编辑应用
// 图片编辑应用中删除原图
async function deleteOriginalImage(imageUri: string) {
try {
await fileManagerService.deleteToTrash(imageUri);
console.info('原图已移到回收站');
} catch (error) {
console.error(`删除原图失败: ${error.code}`);
}
}
在图片编辑应用里,编辑完图片后,如果用户想删除原图,可以用这个功能把原图移到回收站。这样即使用户后悔了,也能从回收站找回来。
适用场景
文件管理服务适合以下场景:
- 文件管理器:文件删除和回收站管理
- 笔记应用:笔记附件的删除
- 图片应用:图片文件的删除
- 文档应用:文档文件的删除
- 下载管理器:下载文件的删除
注意事项
- 文件权限:删除文件前,需要确保对文件有读写权限。可以通过文件选择器让用户授权,这是最简单的方式
- 文件 URI:要确保传入的文件 URI 是有效的,否则会删除失败。URI 格式一般是
file://docs/... - 回收站管理:删除到回收站的文件会占用存储空间,提醒用户定期清理回收站
- 错误处理:要做好错误处理,比如文件不存在、权限不足等情况。不要让程序因为删除失败就崩溃
- 用户体验:删除前最好给用户一个确认提示,避免误删。毕竟移到回收站虽然可以恢复,但多一步确认总是好的
核心流程图
删除文件到回收站的完整流程:
文件管理服务的应用场景:
总结
文件管理服务让你的应用支持"删除到回收站",核心流程:
- 导入文件管理服务模块
- 创建文件选择器,让用户选择要删除的文件
- 调用
deleteToTrash把文件移到回收站 - 处理成功和失败的情况
虽然功能看起来简单,但"删除到回收站"是一个非常实用的功能。它让用户不再担心误删文件,提升了应用的用户体验。如果你的 App 有文件管理功能,一定要加上这个能力。
更多推荐
所有评论(0)