鸿蒙开发实战:【文件管理】

您所在的位置:网站首页 华为手机文件管理如何新建文件夹 鸿蒙开发实战:【文件管理】

鸿蒙开发实战:【文件管理】

2024-07-11 22:40| 来源: 网络整理| 查看: 265

介绍

本示例主要展示了文件管理相关的功能,使用[@ohos.multimedia.medialibrary]、[@ohos.filemanagement.userFileManager] 、[@ohos.fileio] 、[@ohos.file.fs]、[@ohos.app.ability.contextConstant]

等接口,实现了增添文件、删除文件、查找指定类型文件文件、复制并移动文件、切换加密分区和预览图片、监听文件的功能;

效果预览 首页图片列表图片预览文档删除加密分区imageimageimageimageimage

使用说明

在主界面,可以点击图片、视频、文档、音频等按钮进入对应目录的文件列表浏览界面;

在文档列表浏览界面,点击“+”按钮,可以添加文件;

在文档列表浏览界面,长按列表项会出现删除图片,点击删除图标可以删除文件;

在图片文件列表界面,点击图片可以进入图片预览界面。

进入“我的手机”页面前应先安装[MyPhoneFilePage],在主页点击“我的手机”,进入应用目录下。

列表的上方是默认的EL2加密分区的应用根目录下文件列表,点击下方两个按钮“data/app/el3”和“data/app/el4”分别进入EL3和EL4加密分区应用根目录,进入后对文件或文件夹操作与EL2加密分区相同。点击左下角“新建文件夹”按钮,在弹窗中输入文件夹名称,点击弹窗中的“确定”按钮,完成创建。点击新建的文件夹,进入目录,在新目录中点击左下角的“新建文件”,在弹窗的窗口中填写文件名称,然后点击确定,完成创建。点击右上角多选按钮,选择需要重命名的文件(仅选中一个文件时可用),点击重命名,在弹窗中修改文件名称,点击“确定”,完成修改。点击右上角多选按钮,选择需要复制和移动的文件(可多选,并且不可移动到本身的子目录下),选中后点击左下角“复制和移动”按钮,在页面中点击目标目录会进入该目录,在目标目录下点击“移动到这”按钮,完成文件复制和移动。点击右上角多选按钮,选择需要删除的文件,选中后点击右下角“更多”按钮,弹出的菜单中选择“删除”,在弹窗中点击“删除”,即可删除文件。点击右上角多选按钮,选择一项需要修改时间的文件,选中后点击右下角“更多”按钮,弹出的菜单中选择“修改文件(夹)时间”,在弹窗的文本框中输入要修改的时间,点击“确定”,即可修改文件(夹)时间。点击单个文件,可进入文件内容页面,点击右上角编辑按钮,进入编辑模式编辑、修改文件内容,然后点击右上角的保存按钮保存对文件的修改,点击左上角"X"按钮退出编辑模式,点击返回按钮返回上一页。

在主页点击“监听文件”,进入文件监听页面。

点击添加监听按钮,选择IN_CREATE监听,然后点击确定按钮,成功添加IN_CREATE监听。点击添加按钮,成功添加一个文件,触发事件后日志显示为相应日志:event:256,fileName为新增文件的路径。点击停止监听按钮,选择IN_CREATE监听,然后点击确定按钮,成功停止IN_CREATE监听。点击添加按钮,成功添加一个文件,触发事件后日志无变化。点击添加监听按钮,选择IN_DELETE监听,然后点击确定按钮,成功添加IN_DELETE监听。选择要删除的文件item,左滑后点击删除图标,成功删除一个文件,触发事件后日志显示为相应日志:event:512,fileName为删除文件的路径。点击停止监听按钮,选择IN_DELETE监听,然后点击确定按钮,成功停止IN_CREATE监听。选择要删除的文件item,左滑后点击删除图标,成功删除一个文件,触发事件后日志无变化。点击添加监听按钮,选择IN_MODIFY监听,然后点击确定按钮,成功添加IN_MODIFY监听。选择要编辑的文件item,左滑后点击编辑图标,进入文件编辑界面,修改文件名和文件内容,修改之后点击保存图标,页面显示的文件文件大小发生变化,然后点击返回图标后返回文件监听界面,查看触发事件后日志显示为相应日志:event:2,fileName为修改后文件的路径。IN_MODIFY监听只监听文件内容是否发生变化,若单独修改文件名,则不会更新监听日志。点击停止监听按钮,选择IN_MODIFY监听,然后点击确定按钮,成功停止IN_MODIFY监听。选择要编辑的文件item,左滑后点击编辑图标,进入文件编辑界面,修改文件名和文件内容,修改之后点击保存图标,页面显示的文件文件大小发生变化,然后点击返回图标后返回文件监听界面,查看触发事件后日志无变化。 具体实现: 增添文件、删除文件、查找指定类型文件文件和预览图片的功能接口封装在MediaLibraryManager,源码参考:[MediaLibraryManager.ts] /* * Copyright (c) 2022-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import image from '@ohos.multimedia.image' import mediaLibrary from '@ohos.multimedia.mediaLibrary' import Logger from '../../utils/Logger' import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; import type { Permissions } from '@ohos.abilityAccessCtrl'; /** * 主要封装了mediaLibrary库相关的接口 */ class MediaLibraryManager { requestPermission(context): void { let permissions: Array = [ 'ohos.permission.READ_MEDIA', 'ohos.permission.WRITE_MEDIA' ] let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); atManager.requestPermissionsFromUser(context, permissions, (code, result) => { Logger.debug('permissionRequest ' + JSON.stringify(code) + ' Result: ' + JSON.stringify(result)) }) } async getPixelMapByFileAsset(fileAsset: mediaLibrary.FileAsset): Promise { if (fileAsset == undefined) { Logger.error('fileAsset undefined') // 异常情况下统一返回undefined,不建议使用null return undefined } Logger.debug('begin getPixelMapByFileAsset:' + fileAsset.displayName) let fd: number = undefined let pixelMap = undefined try { fd = await fileAsset.open('rw') Logger.debug('getPixelMapByFileAsset fd: ' + fd) let imageSource = image.createImageSource(fd) Logger.debug('imageSource: ' + JSON.stringify(imageSource)) let decodingOptions = { sampleSize: 1, editable: true, desiredSize: { width: 3000, height: 4000 }, rotate: 0, desiredPixelFormat: 3, desiredRegion: { size: { height: 6000, width: 8000 }, x: 0, y: 0 }, index: 0 } pixelMap = await imageSource.createPixelMap(decodingOptions) Logger.debug('pixel size: ' + pixelMap.getPixelBytesNumber()) fileAsset.close(fd) } catch (err) { Logger.debug('err: ' + JSON.stringify(err)) } return pixelMap } getMediaLibrary(context): mediaLibrary.MediaLibrary { return mediaLibrary.getMediaLibrary(context) } async getFileAssets(context, fileType: mediaLibrary.MediaType): Promise { Logger.debug('begin getFileAssets, fileType:' + fileType) let fileKeyObj = mediaLibrary.FileKey let imagesFetchOption = { selections: fileKeyObj.MEDIA_TYPE + '= ?', selectionArgs: [fileType.toString()], } let fetchFileResult: mediaLibrary.FetchFileResult = undefined try { fetchFileResult = await this.getMediaLibrary(context).getFileAssets(imagesFetchOption) Logger.debug('fetchFileResult count:' + fetchFileResult.getCount()) } catch (error) { Logger.error('fetchFileResult Error: ' + JSON.stringify(error)) } return fetchFileResult } async getFileAssetsByName(context, name: string): Promise { Logger.debug('begin getFileAssetsByName: ' + name) let fileKeyObj = mediaLibrary.FileKey let imagesFetchOption = { selections: fileKeyObj.DISPLAY_NAME + '= ?', selectionArgs: [name.toString()], } let fetchFileResult: mediaLibrary.FetchFileResult = undefined let file: mediaLibrary.FileAsset = undefined try { fetchFileResult = await this.getMediaLibrary(context).getFileAssets(imagesFetchOption) Logger.debug('fetchFileResult count:' + fetchFileResult.getCount()) file = await fetchFileResult.getFirstObject() } catch (error) { Logger.error('fetchFileResult Error: ' + JSON.stringify(error)) } return file } async getThumbnail(fileAsset: mediaLibrary.FileAsset): Promise { let thumbnail = undefined try { thumbnail = await fileAsset.getThumbnail() Logger.debug('PixelMap size: ' + thumbnail.getPixelBytesNumber()) } catch (error) { Logger.error('getThumbnail Error: ' + JSON.stringify(error)) } return thumbnail } async createFileAsset(context, mediaType: mediaLibrary.MediaType, dir: mediaLibrary.DirectoryType, fileName: string): Promise { Logger.debug('createFileAsset: ' + fileName) let media = this.getMediaLibrary(context) let path = await media.getPublicDirectory(dir) return await media.createAsset(mediaType, fileName, path) } async deleteFileAsset(fileAsset: mediaLibrary.FileAsset): Promise { Logger.debug('deleteFileAsset:' + fileAsset.displayName); await fileAsset.trash(true); } } export default new MediaLibraryManager()

使用mediaLibrary.getMediaLibrary来获取MediaLibrary对象;

读取每个文件的数据:使用MediaLibrary.getFileAssets读取满足条件的文件集合FetchFileResult,然后调用FetchFileResult.getFirstObject();

创建模拟文件:使用MediaLibrary.getPublicDirectory()获取系统预定的目录,然后使用MediaLibrary.createAsset();

删除指定路径的文件:使用MediaLibrary.deleteAsset();

获取预览图:使用image.createImageSource()创建指定的文件资源ImageSource,然后调用ImageSource.createPixelMap(),接口参考:[@ohos.multimedia.image] 。

MyPhone模块中的文件增删、复制移动、查找功能封装在FileSystem,源码参考:[FileIoManager.ets]。

/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import storageStatistics from '@ohos.file.storageStatistics'; import fileio from '@ohos.fileio'; import prompt from '@ohos.promptAction'; import { BusinessError } from '@ohos.base'; import Logger from '../../utils/Logger'; import { FileType, SubDirectoryType } from '../../mock/local/FileData'; // 大小和单位 const GB_MAGNITUDE: number = 1024 * 1024 * 1024; const MB_MAGNITUDE: number = 1024 * 1024; const KB_MAGNITUDE: number = 1024; const GB_SYMBOL: string = 'GB'; const MB_SYMBOL: string = 'MB'; const KB_SYMBOL: string = 'KB'; const BYTE_SYMBOL: string = 'B'; const TAG: string = 'FileIoManager'; class FileSystem { // 获取文件大小 getFileSize(filePath: string): string { try { let fileSize = fileio.statSync(filePath).size; if (fileSize / GB_MAGNITUDE > 1) { return `${(fileSize / GB_MAGNITUDE).toFixed(2)}${GB_SYMBOL}`; } else if (fileSize / MB_MAGNITUDE > 1) { return `${(fileSize / MB_MAGNITUDE).toFixed(2)}${MB_SYMBOL}`; } else if (fileSize / KB_MAGNITUDE > 1) { return `${(fileSize / KB_MAGNITUDE).toFixed(2)}${KB_SYMBOL}`; } else { return `${fileSize}${BYTE_SYMBOL}`; } } catch (err) { Logger.error(TAG, `getFileSize failed, code is ${err.code}, message is ${err.message}`); throw new Error(`getFileSize failed, code is ${err.code}, message is ${err.message}`); } } /* // 总空间---默认GB async getTotalSize(): Promise { let totalSize: number; try { totalSize = await storageStatistics.getTotalSize(); } catch (err) { let error: BusinessError = err as BusinessError; Logger.error(TAG, `getTotalSize failed, code is ${error.code}, message is ${error.message}`); throw new Error(`getTotalSize failed, code is ${error.code}, message is ${error.message}`); } return `${(totalSize / GB_MAGNITUDE).toFixed(2)}${GB_SYMBOL}`; } // 剩余空间 async getFreeSize(): Promise { let freeSize: number; try { freeSize = await storageStatistics.getFreeSize(); } catch (err) { let error: BusinessError = err as BusinessError; Logger.error(TAG, `getFreeSize failed, code is ${error.code}, message is ${error.message}`); throw new Error(`getFreeSize failed, code is ${error.code}, message is ${error.message}`); } if (freeSize / GB_MAGNITUDE > 1) { return `${(freeSize / GB_MAGNITUDE).toFixed(2)}${GB_SYMBOL}`; } else if (freeSize / MB_MAGNITUDE > 1) { return `${(freeSize / MB_MAGNITUDE).toFixed(2)}${MB_SYMBOL}`; } else if (freeSize / KB_MAGNITUDE > 1) { return `${(freeSize / KB_MAGNITUDE).toFixed(2)}${KB_SYMBOL}`; } else { return `${freeSize}${BYTE_SYMBOL}`; } } */ // 根据沙箱路径打开目录 getSubdirectory(filePath: string): Array { // 获取目录 let dir: fileio.Dir; try { dir = fileio.opendirSync(filePath); } catch (err) { let error: BusinessError = err as BusinessError; Logger.error(TAG, `Open dir of path ${filePath} failed. error code is ${error.code}, message is ${error.message}`); throw new Error(`Open dir of path ${filePath} failed, code is ${error.code}, message is ${error.message}`); } // 读取的结果 let dirent: fileio.Dirent; // 结果数组 class SubDirectory { name: string = ''; type: number = 0; time: Date; childrenNum: number = 0; fileSize: string = ''; constructor(time: Date) { this.time = time; } } let subdirectory: Array = [] do { dirent = dir.readSync(); if (dirent) { let subdirectoryNum: number = 0; let fileSize: string = ''; let time: Date = new Date(); // 如果是文件夹,就读取文件夹中文件的数量 if (dirent.isDirectory()) { subdirectoryNum = this.getSubdirectoryNum(filePath + `${dirent.name}`); time = this.getFileTime(filePath + `${dirent.name}`); } else { // 如果不是文件夹,就读取文件大小和时间 fileSize = this.getFileSize(filePath + `${dirent.name}`); time = this.getFileTime(filePath + `${dirent.name}`); } let item = new SubDirectory(time); item.name = dirent.name; item.type = dirent.isDirectory() ? 1 : 2; item.childrenNum = subdirectoryNum; item.fileSize = fileSize; subdirectory.push(item); } } while (dirent); return subdirectory; } // 获取目录中的子目录个数 getSubdirectoryNum(filePath: string): number { let dir: fileio.Dir; try { dir = fileio.opendirSync(filePath); } catch (err) { let error: BusinessError = err as BusinessError; Logger.error(TAG, `Open dir of path ${filePath} failed. error code is ${error.code}, message is ${error.message}`); throw new Error(`Open dir of path ${filePath} failed, code is ${error.code}, message is ${error.message}`); } // 读取的结果 let dirent: fileio.Dirent; // 记录子目录的个数 let subdirectoryNum = 0; do { dirent = dir.readSync(); if (dirent) { subdirectoryNum++; } } while (dirent); return subdirectoryNum; } // 获取文件修改时间 getFileTime(filePath: string): Date { try { let fileTime = fileio.statSync(filePath).mtime; return new Date(fileTime * 1000); } catch (err) { Logger.error(TAG, `getFileTime failed, code is ${err.code}, message is ${err.message}`); throw new Error(`getFileTime failed, code is ${err.code}, message is ${err.message}`); } } // 创建目录 createDirectory(filePath: string): void { try { fileio.mkdirSync(filePath); } catch (err) { Logger.error(TAG, `create directory failed, code is ${err.code}, message is ${err.message}`); } } // 创建文件 createFile(filePath: string): void { try { fileio.openSync(filePath, 0o100, 0o666); } catch (err) { Logger.error(TAG, `create file failed, code is ${err.code}, message is ${err.message}`); } } // 删除目录和文件---选中项 deleteSelected(dataArray: Map): void { try { dataArray.forEach((value, data) => { if (value === 1) { fileio.rmdirSync(data); } else { fileio.unlinkSync(data); }}) prompt.showToast({ message: $r('app.string.label_delete_success') }); } catch (err) { Logger.error(TAG, `delete failed, code is ${err.code}, message is ${err.message}`); } } // 复制文件 copyFile(filePath: string, newFilePath: string): void { try { // 遍历数据直接copy所有项目 fileio.copyFileSync(filePath, newFilePath); } catch (err) { Logger.error(TAG, `copy file failed, code is ${err.code}, message is ${err.message}`); } } // 重命名文件 renameFile(filePath: string, newFilePath: string): void { try { fileio.renameSync(filePath, newFilePath); } catch (err) { Logger.error(TAG, `rename file failed, code is ${err.code}, message is ${err.message}`); } } // 开始移动文件 startMoveFile(needMoveFiles: Array, newFilePath: string): void { // 遍历数据 needMoveFiles.forEach((file: FileType): void => { // 如果是目录 if (file.type === 1) { // 先创建这个目录 this.createDirectory(`${newFilePath}/${file.fileName}`); // 获取当前文件夹下的所有文件目录 let subdirectory = this.getSubdirectory(`${file.filePath}/`); // 处理为我们想要的格式 let needMoveFiles: Array = []; // 遍历子目录数据 subdirectory.forEach((subdirectoryData: SubDirectoryType) => { let data: FileType = { filePath: `${file.filePath}/${subdirectoryData.name}`, fileName: subdirectoryData.name, type: subdirectoryData.type }; // 逐一添加进去 needMoveFiles.push(data); }) // 使用我们的数据递归 this.startMoveFile(needMoveFiles, `${newFilePath}/${file.fileName}`); } else { this.copyFile(file.filePath, `${newFilePath}/${file.fileName}`); } }) } } export default new FileSystem();

读取文件列表:使用fileio.opendirSync()打开指定目录dir,然后使用dir.readSync()读取文件内容dirent,在调用dirent中相关api获取想要的文件参数;

创建目录:使用fileio.mkdirSync()创建文件夹;

创建文件:使用fileio.openSync()创建文件;

删除选中内容:使用fileio.rmdirSync()删除文件夹,使用fileio.unlinkSync()删除文件;

复制文件:使用fileio.copyFileSync()复制目标文件;

移动文件:使用fileio.mkdirSync()创建指定目录,再递归选中目录中的文件,将内部的文件创建到指定的位置。

修改加密分区:修改应用上下文Context的area,实现当前加密分区的修改。

在Library模块中通过封装FileManager向外提供功能接口,如MediaLibraryManager.getPixelMapByFileAsset(),源码参考:[FileManager.ts]

/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import mediaLibrary from '@ohos.multimedia.mediaLibrary' import image from '@ohos.multimedia.image' import MediaLibraryManager from './medialibrary/MediaLibraryManager' import LocalMockData from '../mock/local/LocalMockData' /** * 文件管理接口,统一封装了各模块对外提供的功能接口 */ class FileManager { /** * 申请文件管理权限 * @param context 上下文对象 */ requestPermission(context): void { MediaLibraryManager.requestPermission(context) } /** * 通过传入文件对象FileAsset,获取到文件中的图片PixelMap对象 * @param fileAsset 文件对象 * @return Promise 返回PixelMap对象 */ async getPixelMapByFileAsset(fileAsset: mediaLibrary.FileAsset): Promise { return await MediaLibraryManager.getPixelMapByFileAsset(fileAsset) } /** * 通过传入文件类型,获取到不同的文件列表信息 * @param context 上下文对象 * @param fileType 文件类型 * @return Promise 返回文件列表信息 */ async getFileAssets(context, fileType: mediaLibrary.MediaType): Promise { return await MediaLibraryManager.getFileAssets(context, fileType) } /** * 通过文件名称获取文件对象 * @param context 上下文对象 * @param name 文件名称 * @return Promise 返回文件对象信息 */ async getFileAssetsByName(context, name: string): Promise { return await MediaLibraryManager.getFileAssetsByName(context, name) } /** * 获取文件缩略图 * @param fileAsset 文件对象 * @return Promise 返回缩略图信息 */ async getThumbnail(fileAsset: mediaLibrary.FileAsset): Promise { return await MediaLibraryManager.getThumbnail(fileAsset) } /** * 创建文件 * @param context 上下文对象 * @param mediaType 文件类型 * @param dir 文件路径 * @param fileName 文件名称 * @return Promise 返回匹配的文件信息 */ async createFileAsset(context, mediaType: mediaLibrary.MediaType, dir: mediaLibrary.DirectoryType, fileName: string): Promise { return await MediaLibraryManager.createFileAsset(context, mediaType, dir, fileName) } /** * 删除文件 * @param fileAsset 文件对象 */ async deleteFileAsset(fileAsset: mediaLibrary.FileAsset): Promise { await MediaLibraryManager.deleteFileAsset(fileAsset); } /** * 创建模拟文件 * @param context 上下文对象 * @param mediaType 文件类型 * @return Promise 返回文件对象 */ async createTxtFileAsset(context): Promise { return await LocalMockData.createFileAsset(context) } /** * 该文件是否支持预览 * @param fileName 文件名 * @return boolean ture表示支持,false表示不支持 */ isSupportPreview(fileName: string): boolean { return LocalMockData.isSupportPreview(fileName) } } export default new FileManager()

如效果预览中的图片列表,读取指定类型的文件:在[FileList.ets]中调用FileManager.getFileAssets();

创建模拟文件:在[FileList.ets] 中调用FileManager.createTxtFileAsset();

删除指定路径的文件:在[FileList.ets] 中调用FileManager.deleteFileAsset();

获取缩略图:在[ThumbnailImage.ets] 中调用FileManager.getThumbnail();

如效果预览中的图片预览,获取预览图:在[ImagePreview.ets] 中调用FileManager.getPixelMapByFileAsset()。

监听文件模块中的文件增删、查找、修改、监听功能封装在MyWatcher。

增加文件、删除文件、监听文件、停止监听文件:在[WatcherFile.ets] 中调用MyWathcer.addFileToWatcher()、MyWathcer.deleteFileToWatcher()、MyWathcer.startWatcher(watcherName)、MyWathcer.stopWatcher();

修改文件:在[EditFile.ets]

中调用MyWatcher.modifyFileToWatcher()。

鸿蒙Next技术知识已更新gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md请前往参考。

QQ浏览器截图20240311144813.png

约束与限制 本示例仅支持标准系统上运行,支持设备:RK3568;本示例为Stage模型,仅支持API11版本SDK,SDK版本号(API Version 11 Beta),镜像版本号(4.1Beta)。本示例需要使用DevEco Studio 版本号(4.0Release)及以上版本才可编译运行。本示例涉及调用系统权限的接口,需要配置允许权限列表,在配置文件中的“allowed-acls”字段中增加"ohos.permission.READ_MEDIA", “ohos.permission.WRITE_MEDIA”, “ohos.permission.FILE_ACCESS_MANAGER”, "ohos.permission.STORAGE_MANAGER"四个权限。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3