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