1/* 2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved. 3 */ 4import fileExtensionInfo from '@ohos.file.fileExtensionInfo'; 5import fileAccess from '@ohos.file.fileAccess'; 6import ObjectUtil from './ObjectUtil'; 7import Logger from '../log/Logger'; 8import StringUtil from './StringUtil'; 9import { FILENAME_MAX_LENGTH, 10 RENAME_CONNECT_CHARACTER } from '../constants/Constant'; 11import MediaLibrary from '@ohos.multimedia.mediaLibrary'; 12 13const TAG = 'FileUtil'; 14 15export class FileUtil { 16 17 /** 18 * uri 格式开头 19 */ 20 static readonly URI_START = 'file://'; 21 22 /** 23 * 根据fileAccess.FileInfo中的mode匹配是否是文件夹 24 * @param mode number 25 * @returns boolean 26 */ 27 public static isFolder(mode: number): boolean { 28 return (mode & fileExtensionInfo.DocumentFlag.REPRESENTS_DIR) === fileExtensionInfo.DocumentFlag.REPRESENTS_DIR; 29 } 30 31 /** 32 * 计算文件夹子文件个数 33 * @param fileIterator fileAccess.FileIterator 34 * @returns number 35 */ 36 public static getChildCountOfFolder(fileIterator: fileAccess.FileIterator): number { 37 let count = 0; 38 if (ObjectUtil.isNullOrUndefined(fileIterator)) { 39 return count; 40 } 41 let isDone: boolean = false; 42 while (!isDone) { 43 let currItem = fileIterator.next(); 44 isDone = currItem.done; 45 if (isDone) { 46 break; 47 } 48 count++; 49 } 50 return count; 51 } 52 53 /** 54 * 获取文件信息 55 * @param uri 文件uri 56 * @param fileAccessHelper fileAccess.FileAccessHelper 57 * @returns fileAccess.FileInfo 58 */ 59 public static async getFileInfoByUri(uri: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> { 60 try { 61 return await fileAccessHelper.getFileInfoFromUri(uri); 62 } catch (err) { 63 Logger.e(TAG, 'getFileInfoByUri err: ' + JSON.stringify(err)); 64 } 65 return null; 66 } 67 68 /** 69 * 获取文件信息 70 * @param relativePath 文件relativePath 71 * @param fileAccessHelper fileAccess.FileAccessHelper 72 * @returns fileAccess.FileInfo 73 */ 74 public static async getFileInfoByRelativePath(relativePath: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> { 75 try { 76 return await fileAccessHelper.getFileInfoFromRelativePath(relativePath); 77 } catch (err) { 78 Logger.e(TAG, 'getFileInfoByRelativePath err: ' + JSON.stringify(err)); 79 } 80 return null; 81 } 82 83 /** 84 * 根据uri获取文件夹子文件列表Iterator 85 * @param uri 86 * @param fileAccessHelper 87 * @returns FileIterator 88 */ 89 public static async getFileIteratorByUri(uri: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileIterator> { 90 try { 91 let fileInfo = await fileAccessHelper.getFileInfoFromUri(uri); 92 return fileInfo.listFile(); 93 } catch (err) { 94 Logger.e(TAG, 'getFileIteratorByUri err: ' + JSON.stringify(err)); 95 } 96 return null; 97 } 98 99 public static getFileAccessHelper(context, wants): fileAccess.FileAccessHelper { 100 try { 101 return fileAccess.createFileAccessHelper(context, wants); 102 } catch (err) { 103 Logger.i(TAG, 'getFileAccessHelper err: ' + JSON.stringify(err)); 104 } 105 return null; 106 } 107 108 public static async getFileAccessHelperAsync(context): Promise<fileAccess.FileAccessHelper> { 109 try { 110 let wants = await fileAccess.getFileAccessAbilityInfo(); 111 return fileAccess.createFileAccessHelper(context, wants); 112 } catch (err) { 113 Logger.i(TAG, 'getFileAccessHelperAsync err: ' + JSON.stringify(err)); 114 } 115 return null; 116 } 117 118 public static getParentRelativePath(relativePath: string): string { 119 let curPath = relativePath; 120 if (StringUtil.isEmpty(relativePath)) { 121 return ''; 122 } 123 124 let index: number = curPath.lastIndexOf('/'); 125 // 去掉最后一个'/' 126 if (index === curPath.length - 1) { 127 curPath = curPath.substr(0, index); 128 } 129 index = curPath.lastIndexOf('/'); 130 if (index <= 0) { 131 return ''; 132 } 133 return curPath.substr(0, index + 1); 134 } 135 136 public static getUsageHabitsKey(prefix: string, suffix: string): string { 137 return prefix + suffix.charAt(0).toLocaleUpperCase() + suffix.substring(1); 138 } 139 140 /** 141 * 是否是uri路径 142 * @param path 路径 143 * @returns 结果 144 */ 145 public static isUriPath(path: string): boolean { 146 if (ObjectUtil.isNullOrUndefined(path)) { 147 return false; 148 } 149 return path.startsWith(this.URI_START); 150 } 151 152 /** 153 * 从目录下获取某个文件名的文件 154 * @param foldrUri 目录uri 155 * @param fileName 文件名 156 * return 结果 157 */ 158 public static async getFileFromFolder(foldrUri: string, fileName, fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> { 159 // 先将目录的信息查询出来 160 let fileInfo: fileAccess.FileInfo = await this.getFileInfoByUri(foldrUri, fileAccessHelper); 161 if (ObjectUtil.isNullOrUndefined(fileInfo)) { 162 return null; 163 } 164 // 构建目标目录下的同名文件的相对路径 165 const destFileRelativePath = fileInfo.relativePath + fileInfo.fileName + '/' + fileName; 166 // 根据相对路径查询相应的文件 167 return await this.getFileInfoByRelativePath(destFileRelativePath, fileAccessHelper); 168 } 169 170 /** 171 * 根据FileInfo获取当前文件的文件夹 172 * 173 * @param fileInfo 文件对象 174 * @returns 返回当前文件的文件夹 175 */ 176 public static getCurrentFolderByFileInfo(fileInfo: fileAccess.FileInfo): string { 177 if (fileInfo !== null) { 178 let path = fileInfo.relativePath; 179 return FileUtil.getCurrentDir(path, FileUtil.isFolder(fileInfo.mode)); 180 } 181 return ""; 182 } 183 184 public static async createFolder(fileAccessHelper: fileAccess.FileAccessHelper, parentUri: string, name: string): Promise<{code, uri}> { 185 let uri: string = ''; 186 let code: any; 187 try { 188 uri = await fileAccessHelper.mkDir(parentUri, name); 189 } catch (error) { 190 code = error.code; 191 Logger.e(TAG, 'createFolder error occurred:' + error.code + ', ' + error.message); 192 } 193 return {code: code, uri: uri}; 194 } 195 196 public static async hardDelete(uri: string, mediaLibrary: MediaLibrary.MediaLibrary): Promise<boolean> { 197 if (ObjectUtil.isNullOrUndefined(mediaLibrary)) { 198 return false; 199 } 200 try { 201 await mediaLibrary.deleteAsset(uri); 202 return true; 203 } catch (e) { 204 Logger.e(TAG, 'hardDelete error: ' + JSON.stringify(e)); 205 } 206 return false; 207 } 208 209 /** 210 * 重命名 211 * @param fileAccessHelper FileAccessHelper 212 * @param oldUri oldUri 213 * @param newName newName 214 * @returns {err, uri} 215 */ 216 public static async rename(fileAccessHelper: fileAccess.FileAccessHelper, oldUri: string, newName: string): Promise<{err, uri}> { 217 let uri: string = ''; 218 let err: any; 219 try { 220 uri = await fileAccessHelper.rename(oldUri, newName); 221 } catch (error) { 222 err = {code: error.code, message: error.message}; 223 Logger.e(TAG, 'rename error occurred:' + error.code + ', ' + error.message); 224 } 225 return {err: err, uri: uri}; 226 } 227 228 public static async createFile(fileAccessHelper: fileAccess.FileAccessHelper, parentUri: string, fileName: string): Promise<{err, uri}> { 229 let retUri: string = ''; 230 let err: any; 231 try { 232 Logger.i(TAG, 'createFile ' + fileAccessHelper + '; ' + parentUri + " ; " + fileName); 233 retUri = await fileAccessHelper.createFile(parentUri, fileName); 234 } catch (e) { 235 Logger.e(TAG, 'createFile error: ' + e.code + ', ' + e.message); 236 err = {code: e.code, message: e.message}; 237 } 238 return {err: err, uri: retUri}; 239 } 240 241 public static hasSubFolder(loadPath: string, curFolderPath: string): boolean { 242 if (!StringUtil.isEmpty(loadPath)) { 243 if (!StringUtil.isEmpty(curFolderPath)) { 244 loadPath = FileUtil.getPathWithFileSplit(loadPath); 245 curFolderPath = FileUtil.getPathWithFileSplit(curFolderPath); 246 if (loadPath.startsWith(curFolderPath)) { 247 return true; 248 } 249 } 250 } 251 return false; 252 } 253 254 public static getPathWithFileSplit(path: string): string { 255 let fileSplit: string = '/'; 256 if (path && !path.endsWith(fileSplit)) { 257 path = path + fileSplit; 258 } 259 return path; 260 } 261 262 public static loadSubFinish(loadPath: string, curFolderPath: string, maxLevel: number): boolean { 263 let fileSplit: string = '/'; 264 if (!StringUtil.isEmpty(loadPath)) { 265 if (!loadPath.endsWith(fileSplit)) { 266 loadPath = loadPath + fileSplit; 267 } 268 269 let folders = curFolderPath.split(fileSplit); 270 271 if ((curFolderPath + fileSplit) === loadPath || folders.length >= maxLevel) { 272 return true; 273 } 274 } 275 return false; 276 } 277 278 public static renameFile(fileName: string, renameCount: number, suffix: string): string { 279 if (ObjectUtil.isNullOrUndefined(fileName)) { 280 return fileName; 281 } 282 let newName = fileName; 283 if (renameCount > 0) { 284 newName = fileName + RENAME_CONNECT_CHARACTER + renameCount; 285 let strLen = newName.length + suffix.length; 286 // 字符长度大于最大长度 287 if (strLen > FILENAME_MAX_LENGTH) { 288 // 计算需要裁剪的长度 289 let subLen = strLen - FILENAME_MAX_LENGTH + 1; 290 newName = fileName.substring(0, fileName.length - subLen) + RENAME_CONNECT_CHARACTER + renameCount; 291 } 292 } 293 return newName + suffix; 294 } 295 296 public static getFileNameReName(fileName: string): string[] { 297 if (StringUtil.isEmpty(fileName)) { 298 return null; 299 } 300 let index = fileName.lastIndexOf(RENAME_CONNECT_CHARACTER); 301 if (index === -1) { 302 return null; 303 } 304 let str = fileName.substring(index + 1, fileName.length); 305 let name = fileName.substring(0, index); 306 return [name, str]; 307 } 308 309 public static getCurrentDir(path: string, isFolder: boolean): string { 310 if (isFolder) { 311 return path; 312 } 313 if (path) { 314 let index: number = path.lastIndexOf('/'); 315 let len: number = path.length; 316 if (len > 1 && index > 1) { 317 return path.substring(0, index); 318 } 319 } 320 return path; 321 } 322 323 public static getUriPath(path: string): string { 324 if (path && FileUtil.isUriPath(path)) { 325 return path; 326 } 327 return null; 328 } 329}