/* * Copyright (c) 2021-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 fileExtensionInfo from '@ohos.file.fileExtensionInfo'; import fileAccess from '@ohos.file.fileAccess'; import ObjectUtil from './ObjectUtil'; import Logger from '../log/Logger'; import StringUtil from './StringUtil'; import { FILENAME_MAX_LENGTH, RENAME_CONNECT_CHARACTER } from '../constants/Constant'; import fs from '@ohos.file.fs'; import FileUri from '@ohos.file.fileuri'; import { photoAccessHelper } from '@kit.MediaLibraryKit'; const TAG = 'FileUtil'; export class ErrCodeMessage { code: number = 0; message: string = ''; } export class ErrUri { err: ErrCodeMessage = new ErrCodeMessage(); uri: string = ''; } export class FileUtil { /** * uri 格式开头 */ static readonly URI_START = 'file://'; /** * 根据fileAccess.FileInfo中的mode匹配是否是文件夹 * @param mode number * @returns boolean */ public static isFolder(mode: number): boolean { return (mode & fileExtensionInfo.DocumentFlag.REPRESENTS_DIR) === fileExtensionInfo.DocumentFlag.REPRESENTS_DIR; } /** * 计算文件夹子文件个数 * @param fileIterator fileAccess.FileIterator * @returns number */ public static getChildCountOfFolder(fileIterator: fileAccess.FileIterator): number { let count = 0; if (ObjectUtil.isNullOrUndefined(fileIterator)) { return count; } let isDone: boolean = false; while (!isDone) { let currItem = fileIterator.next(); isDone = currItem.done; if (isDone) { break; } count++; } return count; } /** * 获取文件信息 * @param uri 文件uri * @param fileAccessHelper fileAccess.FileAccessHelper * @returns fileAccess.FileInfo */ public static async getFileInfoByUri(uri: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise { try { return await fileAccessHelper.getFileInfoFromUri(uri); } catch (err) { Logger.e(TAG, 'getFileInfoByUri err: ' + JSON.stringify(err)); } return null; } /** * 获取文件信息 * @param relativePath 文件relativePath * @param fileAccessHelper fileAccess.FileAccessHelper * @returns fileAccess.FileInfo */ public static async getFileInfoByRelativePath(relativePath: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise { try { return await fileAccessHelper.getFileInfoFromRelativePath(relativePath); } catch (err) { Logger.e(TAG, 'getFileInfoByRelativePath err: ' + JSON.stringify(err)); } return null; } /** * 根据uri获取文件夹子文件列表Iterator * @param uri * @param fileAccessHelper * @returns FileIterator */ public static async getFileIteratorByUri(uri: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise { try { let fileInfo = await fileAccessHelper.getFileInfoFromUri(uri); return fileInfo.listFile(); } catch (err) { Logger.e(TAG, 'getFileIteratorByUri err: ' + JSON.stringify(err)); } return null; } public static getFileAccessHelper(context, wants): fileAccess.FileAccessHelper { try { return fileAccess.createFileAccessHelper(context, wants); } catch (err) { Logger.i(TAG, 'getFileAccessHelper err: ' + JSON.stringify(err)); } return null; } public static async getFileAccessHelperAsync(context): Promise { try { let wants = await fileAccess.getFileAccessAbilityInfo(); return fileAccess.createFileAccessHelper(context, wants); } catch (err) { Logger.i(TAG, 'getFileAccessHelperAsync err: ' + JSON.stringify(err)); } return null; } public static getParentRelativePath(relativePath: string): string { let curPath = relativePath; if (StringUtil.isEmpty(relativePath)) { return ''; } let index: number = curPath.lastIndexOf('/'); // 去掉最后一个'/' if (index === curPath.length - 1) { curPath = curPath.substr(0, index); } index = curPath.lastIndexOf('/'); if (index <= 0) { return ''; } return curPath.substr(0, index + 1); } public static getUsageHabitsKey(prefix: string, suffix: string): string { return prefix + suffix.charAt(0).toLocaleUpperCase() + suffix.substring(1); } /** * 是否是uri路径 * @param path 路径 * @returns 结果 */ public static isUriPath(path: string): boolean { if (ObjectUtil.isNullOrUndefined(path)) { return false; } return path.startsWith(this.URI_START); } /** * 从目录下获取某个文件名的文件 * @param foldrUri 目录uri * @param fileName 文件名 * return 结果 */ public static async getFileFromFolder(foldrUri: string, fileName, fileAccessHelper: fileAccess.FileAccessHelper): Promise { // 先将目录的信息查询出来 let fileInfo: fileAccess.FileInfo = await this.getFileInfoByUri(foldrUri, fileAccessHelper); if (ObjectUtil.isNullOrUndefined(fileInfo)) { return null; } // 构建目标目录下的同名文件的相对路径 const destFileRelativePath = fileInfo.relativePath + fileInfo.fileName + '/' + fileName; // 根据相对路径查询相应的文件 return await this.getFileInfoByRelativePath(destFileRelativePath, fileAccessHelper); } /** * 根据FileInfo获取当前文件的文件夹 * * @param fileInfo 文件对象 * @returns 返回当前文件的文件夹 */ public static getCurrentFolderByFileInfo(fileInfo: fileAccess.FileInfo): string { if (fileInfo !== null) { let path = fileInfo.relativePath; return FileUtil.getCurrentDir(path, FileUtil.isFolder(fileInfo.mode)); } return ""; } public static async createFolder(fileAccessHelper: fileAccess.FileAccessHelper, parentUri: string, name: string): Promise<{ code, uri }> { let uri: string = ''; let code: any; try { uri = await fileAccessHelper.mkDir(parentUri, name); } catch (error) { code = error.code; Logger.e(TAG, 'createFolder error occurred:' + error.code + ', ' + error.message); } return { code: code, uri: uri }; } public static async hardDelete(uri: string): Promise { try { await photoAccessHelper.MediaAssetChangeRequest.deleteAssets(globalThis.abilityContext , [uri]); return true; } catch (e) { Logger.e(TAG, 'hardDelete error: ' + JSON.stringify(e)); } return false; } /** * 重命名 * @param fileAccessHelper FileAccessHelper * @param oldUri oldUri * @param newName newName * @returns {err, uri} */ public static async rename(fileAccessHelper: fileAccess.FileAccessHelper, oldUri: string, newName: string): Promise { let errUri: ErrUri = new ErrUri(); try { errUri.uri = await fileAccessHelper.rename(oldUri, newName); } catch (error) { errUri.err = { code: error.code, message: error.message }; Logger.e(TAG, 'rename error occurred:' + error.code + ', ' + error.message); } return errUri; } public static async createFile(fileAccessHelper: fileAccess.FileAccessHelper, parentUri: string, fileName: string): Promise { let errUri: ErrUri = new ErrUri(); try { Logger.i(TAG, 'createFile ' + fileAccessHelper + '; ' + parentUri + " ; " + fileName); errUri.uri = await fileAccessHelper.createFile(parentUri, fileName); } catch (e) { Logger.e(TAG, 'createFile error: ' + e.code + ', ' + e.message); errUri.err = { code: e.code, message: e.message }; } return errUri; } public static hasSubFolder(loadPath: string, curFolderPath: string): boolean { if (!StringUtil.isEmpty(loadPath)) { if (!StringUtil.isEmpty(curFolderPath)) { loadPath = FileUtil.getPathWithFileSplit(loadPath); curFolderPath = FileUtil.getPathWithFileSplit(curFolderPath); if (loadPath.startsWith(curFolderPath)) { return true; } } } return false; } public static getPathWithFileSplit(path: string): string { let fileSplit: string = '/'; if (path && !path.endsWith(fileSplit)) { path = path + fileSplit; } return path; } public static loadSubFinish(loadPath: string, curFolderPath: string, maxLevel: number): boolean { let fileSplit: string = '/'; if (!StringUtil.isEmpty(loadPath)) { if (!loadPath.endsWith(fileSplit)) { loadPath = loadPath + fileSplit; } let folders = curFolderPath.split(fileSplit); if ((curFolderPath + fileSplit) === loadPath || folders.length >= maxLevel) { return true; } } return false; } public static renameFile(fileName: string, renameCount: number, suffix: string): string { if (ObjectUtil.isNullOrUndefined(fileName)) { return fileName; } let newName = fileName; if (renameCount > 0) { newName = fileName + RENAME_CONNECT_CHARACTER + renameCount; let strLen = newName.length + suffix.length; // 字符长度大于最大长度 if (strLen > FILENAME_MAX_LENGTH) { // 计算需要裁剪的长度 let subLen = strLen - FILENAME_MAX_LENGTH + 1; newName = fileName.substring(0, fileName.length - subLen) + RENAME_CONNECT_CHARACTER + renameCount; } } return newName + suffix; } public static getFileNameReName(fileName: string): string[] { if (StringUtil.isEmpty(fileName)) { return null; } let index = fileName.lastIndexOf(RENAME_CONNECT_CHARACTER); if (index === -1) { return null; } let str = fileName.substring(index + 1, fileName.length); let name = fileName.substring(0, index); return [name, str]; } public static getCurrentDir(path: string, isFolder: boolean): string { if (isFolder) { return path; } if (path) { let index: number = path.lastIndexOf('/'); let len: number = path.length; if (len > 1 && index > 1) { return path.substring(0, index); } } return path; } public static getUriPath(path: string): string { if (path && FileUtil.isUriPath(path)) { return path; } return null; } /** * 根据文件的沙箱路径获取文件uri * @param path 文件的沙箱路径 * @returns 文件的uri */ public static getUriFromPath(path: string): string { let uri = ''; try { // 该接口如果以’/'结尾,返回的uri会以‘/'结尾 uri = FileUri.getUriFromPath(path); } catch (error) { Logger.e(TAG, 'getUriFromPath fail, error:' + JSON.stringify(error)); } return uri; } /** * 将文件uri转换成FileUri对象 */ public static getFileUriObjectFromUri(uri: string): FileUri.FileUri | undefined { let fileUriObject: FileUri.FileUri | undefined; try { fileUriObject = new FileUri.FileUri(uri); } catch (error) { Logger.e(TAG, 'getFileUriObjectFromUri fail, error:' + JSON.stringify(error)); } return fileUriObject; } /** * 通过将文件uri转换成FileUri对象获取文件的沙箱路径 * @param uri 文件uri * @returns 文件的沙箱路径 */ public static getPathFromUri(uri: string): string { let path = ''; const fileUriObj = FileUtil.getFileUriObjectFromUri(uri); if (!!fileUriObj) { path = fileUriObj.path; } return path; } /** * 创建文件夹 * @param parentFolderUri 父目录uri * @param newFolderName 新文件夹名 * @returns 新文件夹uri */ public static createFolderByFs(parentFolderUri: string, newFolderName: string): string { try { const parentFolderPath = FileUtil.getPathFromUri(parentFolderUri); const newFolderPath = parentFolderPath + '/' + newFolderName; fs.mkdirSync(newFolderPath); return FileUtil.getUriFromPath(newFolderPath); } catch (error) { Logger.e(TAG, 'createFolderByFs fail, error:' + JSON.stringify(error)); throw error as Error; } } }