自制一款鸿蒙应用文件管理器

在涉及应用内部存储的开发时,常常翻阅手机自带的文件管理检查。正好在学习文件管理的接口,想着实现一个第三方组件用于当前应用的文件查看和管理。
介绍
如下:
类型:第三方组件.ets
语言框架:arkts
api 版本:harmonyos sdk 8
模型:fa
目前已实现的功能:
上下级文件的浏览
查看文件基本信息(名称、大小、修改日期)
删除文件
文件路径显示
组件宽高、横竖屏自适应
使用示例
    代码如下:
//导入组件import { filer } from '../views/filemanager';//调用组件struct index{    ...    column() {      filer()      // filer({width:'100%',height:'100%'}) // 可传入宽高参数    }.width('100%').height('100%')}  
接下来是实现思路的简单分析,有兴趣的可以看一下源代码。
实现思路
    主要涉及两个方面:
接口函数
交互设计(后续出)
①接口函数
接口方法整理:接口函数涉及到文件目录的访问、文件信息的读取、文件的删除等,文档接口非常多,但只需认识基本的几个接口就够用了。
文档传送门:@ohos.fileio (文件管理)-文件管理-接口参考(arkts及js api)-手机、平板、智慧屏和智能穿戴开发-arkts api参考-harmonyos应用开发
https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-fileio-0000001333640945#zh-cn_topic_0000001333640945__%e5%af%bc%e5%85%a5%e6%a8%a1%e5%9d%97import fileio from '@ohos.fileio';import featureability from '@ohos.ability.featureability';let context = featureability.getcontext();// fa模型获取context模块// let context = globalthis.abilitycontext;// stage模型获取context模块这里给大家整理了基本的接口:
下面是底层开放访问的三大目录:
以上接口返回的路径都是以 /data/user/0/包名/ 开头,是多种访问路径的其中一种。
ps:stage模型中提供的目录访问接口与 fa 不同,有三个目录:tempdir、cachedir、filesdir,还有其它类型的目录如数据库目录等。
具体参考 gitee 文档 context 模块:
https://gitee.com/openharmony/docs/blob/8504866055592da2a92a539ab0074c93642d6aa1/zh-cn/application-dev/reference/apis/js-apis-inner-application-context.mdapi 9 还提供了新的文件管理接口,但是接口方法大同小异:import fs from '@ohos.file.fs';  
②代码思路
以数据结构中最基本的树状结构数组来保存文件的父子关系和个体信息,每一次的文件操作相当于维护这样的一个文件树。
每一个文件对应一个 node 结点:
type node = {  id: number, // 当前编号  filename: string, // 文件名称  filetype: filetype, // 文件类型  path: string, // 完整有效访问路径  parentid: number, // 父级编号  size: number, // 文件大小  mtime: number // 修改时间}enum filetype {  'dir' = 0,// 文件夹  'file' = 1,// 普通文件  'else' = 2// 其它类型文件}  主要变量://--- 文件树相关变量private relativepath: string = '' //内部存储器上此应用程序的文件目录private absolutepath: string = '' //根目录private cachepath: string = '' //内部存储目录private historynodestree: array = [] // 保存所有文件信息,即文件树,需要维护private rootnodes: array = [] // 保存三大目录根的信息,不可继续往上访问//--- 与ui相关的变量@state private curnodes: array = [] // 展示当前层级所有文件@state private patharray: array = [''] // 路径分割数组,用于组件顶部路径展示@state @watch('oncurparentnodechange') curparentnode: node = undefined // 保存上一级结点,方便结点和路径更新private width: length = '100%' // 组件默认宽private height: length = '100%' // 组件默认高维护文件树方法:backtodir() // 返回上一级deleteselecteddir() // 删除操作unlink() // 删除文件rmdir() // 删除目录openselecteddir() // 打开目录,进入下一级addnewnode() // 添加新结点getorcreatelocaldir() // 获取应用根目录getfilesdir() // 获取file://根目录getcachedir() // 获取cache://根目录工具方法:handlefilesize() // 文件字节格式转换filesizetransform() // 文件字节格式转换timestamptodate() // 时间戳与常用时间格式转换下面是部分与 fileio 密切相关的函数: 打开选中目录:
openselecteddir(parentnode: node): void { // 传参:待打开的目录结点  this.curparentnode = parentnode // 更新保存当前结点的父结点  fileio.opendir(parentnode.path).then(dir => { // 打开文件夹    let direct = dir.readsync() // 读取下一个子文件    this.curnodes.length = 0 // 刷新ui    while (direct !== undefined) { // 找出所有子文件,逐个构造node结点      this.addnewnode(parentnode, direct)      direct = dir.readsync()    }    dir.closesync() // 关闭目录  }).catch(() => {})}  
添加新文件结点:
addnewnode(parentnode: node, direct?: fileio.dirent): void { // 构造node结点并维护文件树  if (!direct) { // 入参重载    this.curnodes.push(parentnode)    this.historynodestree.push(parentnode)    return  }  let path = parentnode.path + '/' + direct.name  let filetype = direct.isdirectory() // 是否为文件夹类型  let size: number = -1  let filestat = fileio.statsync(path) // 获取文件具体信息  if (!filetype && filestat.isfile()) { // 普通文件外的文件类型不展示字节大小    size = filestat.size  }  let newnode: node = { // 构造node结点    path: path,    filename: direct.name,    filetype: filetype ? 0 : direct.isfile() ? 1 : 2,    parentid: parentnode.id,    id: (this.historynodestree.length + 1),    size: size,    mtime: filestat.mtime  }  this.curnodes.push(newnode) // 更新当前ui  this.historynodestree.push(newnode) // 维护文件树  console.info('fsj--- addnewnode: ' + newnode.filename)}  
删除目录(包含删除文件操作):
async rmdir(node: node) {    let path = node.path    await this.bfsrmdir(path) // 删除所有子文件、子目录后    fileio.rmdir(node.path).then(() => { // 再删除该目录        showtoast('删除成功')        this.curnodes = this.curnodes.filter(item => item.id != node.id)    }).catch((err) => {        showtoast('删除失败: ' + json.stringify(err))    })}async bfsrmdir(path: string): promise { // 深度搜索遍历,删除该目录下的所有子文件、子目录    return new promise((res) => {        fileio.opendir(path).then(async (dir) => {            let direct = dir.readsync()            while (direct !== undefined) {                let sonpath = path + '/' + direct.name                if (fileio.statsync(sonpath).isdirectory()) {                    await this.bfsrmdir(sonpath)                }                fileio.unlinksync(sonpath)                direct = dir.readsync()            }            dir.closesync()            res()        })    })}  
ps: 当目录存在子文件时,不允许直接调用 rmdir() 删除该目录,需要先删除所有子文件、子目录,否则会报错 code:39,这里我采用深度搜索遍历的方法删除所有子文件、子目录。
错误码参考链接 (这是 3.1 beta 的文档,终于可以清晰地知道错误码的信息了。)
https://developer.harmonyos.com/cn/docs/documentation/doc-references-v3/errorcode-filemanagement-0000001427585212-v3?catalogversion=v3   
效果图
上下浏览:
删除操作:


华为荣耀9怎么样?荣耀9颜值与性能并存的毕业季换机首选,玻璃材质的外壳手感丝滑,让你拿得起却舍不得放下
电源插座安装规范_电源插座安装注意事项
长方集团为何如此急于出售惠州长方?
荣耀20i对比美颜APP 哪个更强
减速电机齿轮磨齿加工方法
自制一款鸿蒙应用文件管理器
深入探讨功率半导体器件的未来发展趋势
带涡轮开关的插槽车控制器电路
无纺布在线检测设备的主要技术参数是什么
苹果高端头戴耳机或今年亮相
FMAD CP:带中性线的三相滤波器
一汽马自达究竟凭借什么逆流而上?
BUCK电源电路设计测试过程分享
详解nRF24L01无线收发模块设计
锂电池保护板的几种工作状态分析
小米6放大招, 骁龙835的产量将限制不了小米手机的产能!
浅析SAN存储层面的信创转型与架构升级方案
肥料有机质含量测定仪的仪器特点是什么
苹果Mac mini2020正式发布:搭载M1芯片
航天2.5 GHz直接转换正交调制器AD8346S