• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, RENAME_CONNECT_CHARACTER } from '../constants/Constant';
22import fs from '@ohos.file.fs';
23import FileUri from '@ohos.file.fileuri';
24import { photoAccessHelper } from '@kit.MediaLibraryKit';
25
26const TAG = 'FileUtil';
27
28export class ErrCodeMessage {
29  code: number = 0;
30  message: string = '';
31
32}
33export class ErrUri {
34  err: ErrCodeMessage = new ErrCodeMessage();
35  uri: string = '';
36}
37
38export class FileUtil {
39  /**
40   * uri 格式开头
41   */
42  static readonly URI_START = 'file://';
43
44  /**
45   * 根据fileAccess.FileInfo中的mode匹配是否是文件夹
46   * @param mode number
47   * @returns boolean
48   */
49  public static isFolder(mode: number): boolean {
50    return (mode & fileExtensionInfo.DocumentFlag.REPRESENTS_DIR) === fileExtensionInfo.DocumentFlag.REPRESENTS_DIR;
51  }
52
53  /**
54   * 计算文件夹子文件个数
55   * @param fileIterator fileAccess.FileIterator
56   * @returns number
57   */
58  public static getChildCountOfFolder(fileIterator: fileAccess.FileIterator): number {
59    let count = 0;
60    if (ObjectUtil.isNullOrUndefined(fileIterator)) {
61      return count;
62    }
63    let isDone: boolean = false;
64    while (!isDone) {
65      let currItem = fileIterator.next();
66      isDone = currItem.done;
67      if (isDone) {
68        break;
69      }
70      count++;
71    }
72    return count;
73  }
74
75  /**
76   * 获取文件信息
77   * @param uri 文件uri
78   * @param fileAccessHelper fileAccess.FileAccessHelper
79   * @returns fileAccess.FileInfo
80   */
81  public static async getFileInfoByUri(uri: string,
82    fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> {
83    try {
84      return await fileAccessHelper.getFileInfoFromUri(uri);
85    } catch (err) {
86      Logger.e(TAG, 'getFileInfoByUri err: ' + JSON.stringify(err));
87    }
88    return null;
89  }
90
91  /**
92   * 获取文件信息
93   * @param relativePath 文件relativePath
94   * @param fileAccessHelper fileAccess.FileAccessHelper
95   * @returns fileAccess.FileInfo
96   */
97  public static async getFileInfoByRelativePath(relativePath: string,
98    fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> {
99    try {
100      return await fileAccessHelper.getFileInfoFromRelativePath(relativePath);
101    } catch (err) {
102      Logger.e(TAG, 'getFileInfoByRelativePath err: ' + JSON.stringify(err));
103    }
104    return null;
105  }
106
107  /**
108   * 根据uri获取文件夹子文件列表Iterator
109   * @param uri
110   * @param fileAccessHelper
111   * @returns FileIterator
112   */
113  public static async getFileIteratorByUri(uri: string,
114    fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileIterator> {
115    try {
116      let fileInfo = await fileAccessHelper.getFileInfoFromUri(uri);
117      return fileInfo.listFile();
118    } catch (err) {
119      Logger.e(TAG, 'getFileIteratorByUri err: ' + JSON.stringify(err));
120    }
121    return null;
122  }
123
124  public static getFileAccessHelper(context, wants): fileAccess.FileAccessHelper {
125    try {
126      return fileAccess.createFileAccessHelper(context, wants);
127    } catch (err) {
128      Logger.i(TAG, 'getFileAccessHelper err: ' + JSON.stringify(err));
129    }
130    return null;
131  }
132
133  public static async getFileAccessHelperAsync(context): Promise<fileAccess.FileAccessHelper> {
134    try {
135      let wants = await fileAccess.getFileAccessAbilityInfo();
136      return fileAccess.createFileAccessHelper(context, wants);
137    } catch (err) {
138      Logger.i(TAG, 'getFileAccessHelperAsync err: ' + JSON.stringify(err));
139    }
140    return null;
141  }
142
143  public static getParentRelativePath(relativePath: string): string {
144    let curPath = relativePath;
145    if (StringUtil.isEmpty(relativePath)) {
146      return '';
147    }
148
149    let index: number = curPath.lastIndexOf('/');
150    // 去掉最后一个'/'
151    if (index === curPath.length - 1) {
152      curPath = curPath.substr(0, index);
153    }
154    index = curPath.lastIndexOf('/');
155    if (index <= 0) {
156      return '';
157    }
158    return curPath.substr(0, index + 1);
159  }
160
161  public static getUsageHabitsKey(prefix: string, suffix: string): string {
162    return prefix + suffix.charAt(0).toLocaleUpperCase() + suffix.substring(1);
163  }
164
165  /**
166   * 是否是uri路径
167   * @param path 路径
168   * @returns 结果
169   */
170  public static isUriPath(path: string): boolean {
171    if (ObjectUtil.isNullOrUndefined(path)) {
172      return false;
173    }
174    return path.startsWith(this.URI_START);
175  }
176
177  /**
178   * 从目录下获取某个文件名的文件
179   * @param foldrUri 目录uri
180   * @param fileName 文件名
181   * return 结果
182   */
183  public static async getFileFromFolder(foldrUri: string, fileName,
184    fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> {
185    // 先将目录的信息查询出来
186    let fileInfo: fileAccess.FileInfo = await this.getFileInfoByUri(foldrUri, fileAccessHelper);
187    if (ObjectUtil.isNullOrUndefined(fileInfo)) {
188      return null;
189    }
190    // 构建目标目录下的同名文件的相对路径
191    const destFileRelativePath = fileInfo.relativePath + fileInfo.fileName + '/' + fileName;
192    // 根据相对路径查询相应的文件
193    return await this.getFileInfoByRelativePath(destFileRelativePath, fileAccessHelper);
194  }
195
196  /**
197   * 根据FileInfo获取当前文件的文件夹
198   *
199   * @param fileInfo 文件对象
200   * @returns 返回当前文件的文件夹
201   */
202  public static getCurrentFolderByFileInfo(fileInfo: fileAccess.FileInfo): string {
203    if (fileInfo !== null) {
204      let path = fileInfo.relativePath;
205      return FileUtil.getCurrentDir(path, FileUtil.isFolder(fileInfo.mode));
206    }
207    return "";
208  }
209
210  public static async createFolder(fileAccessHelper: fileAccess.FileAccessHelper, parentUri: string,
211    name: string): Promise<{
212    code,
213    uri
214  }> {
215    let uri: string = '';
216    let code: any;
217    try {
218      uri = await fileAccessHelper.mkDir(parentUri, name);
219    } catch (error) {
220      code = error.code;
221      Logger.e(TAG, 'createFolder error occurred:' + error.code + ', ' + error.message);
222    }
223    return { code: code, uri: uri };
224  }
225
226  public static async hardDelete(uri: string): Promise<boolean> {
227    try {
228      await photoAccessHelper.MediaAssetChangeRequest.deleteAssets(globalThis.abilityContext , [uri]);
229      return true;
230    } catch (e) {
231      Logger.e(TAG, 'hardDelete error: ' + JSON.stringify(e));
232    }
233    return false;
234  }
235
236  /**
237   * 重命名
238   * @param fileAccessHelper FileAccessHelper
239   * @param oldUri oldUri
240   * @param newName newName
241   * @returns {err, uri}
242   */
243  public static async rename(fileAccessHelper: fileAccess.FileAccessHelper, oldUri: string, newName: string): Promise<ErrUri> {
244    let errUri: ErrUri = new ErrUri();
245    try {
246      errUri.uri = await fileAccessHelper.rename(oldUri, newName);
247    } catch (error) {
248      errUri.err = { code: error.code, message: error.message };
249      Logger.e(TAG, 'rename error occurred:' + error.code + ', ' + error.message);
250    }
251    return errUri;
252  }
253
254  public static async createFile(fileAccessHelper: fileAccess.FileAccessHelper, parentUri: string,
255    fileName: string): Promise<ErrUri> {
256    let errUri: ErrUri = new ErrUri();
257    try {
258      Logger.i(TAG, 'createFile ' + fileAccessHelper + '; ' + parentUri + " ; " + fileName);
259      errUri.uri = await fileAccessHelper.createFile(parentUri, fileName);
260    } catch (e) {
261      Logger.e(TAG, 'createFile error: ' + e.code + ', ' + e.message);
262      errUri.err = { code: e.code, message: e.message };
263    }
264    return errUri;
265  }
266
267  public static hasSubFolder(loadPath: string, curFolderPath: string): boolean {
268    if (!StringUtil.isEmpty(loadPath)) {
269      if (!StringUtil.isEmpty(curFolderPath)) {
270        loadPath = FileUtil.getPathWithFileSplit(loadPath);
271        curFolderPath = FileUtil.getPathWithFileSplit(curFolderPath);
272        if (loadPath.startsWith(curFolderPath)) {
273          return true;
274        }
275      }
276    }
277    return false;
278  }
279
280  public static getPathWithFileSplit(path: string): string {
281    let fileSplit: string = '/';
282    if (path && !path.endsWith(fileSplit)) {
283      path = path + fileSplit;
284    }
285    return path;
286  }
287
288  public static loadSubFinish(loadPath: string, curFolderPath: string, maxLevel: number): boolean {
289    let fileSplit: string = '/';
290    if (!StringUtil.isEmpty(loadPath)) {
291      if (!loadPath.endsWith(fileSplit)) {
292        loadPath = loadPath + fileSplit;
293      }
294
295      let folders = curFolderPath.split(fileSplit);
296
297      if ((curFolderPath + fileSplit) === loadPath || folders.length >= maxLevel) {
298        return true;
299      }
300    }
301    return false;
302  }
303
304  public static renameFile(fileName: string, renameCount: number, suffix: string): string {
305    if (ObjectUtil.isNullOrUndefined(fileName)) {
306      return fileName;
307    }
308    let newName = fileName;
309    if (renameCount > 0) {
310      newName = fileName + RENAME_CONNECT_CHARACTER + renameCount;
311      let strLen = newName.length + suffix.length;
312      // 字符长度大于最大长度
313      if (strLen > FILENAME_MAX_LENGTH) {
314        // 计算需要裁剪的长度
315        let subLen = strLen - FILENAME_MAX_LENGTH + 1;
316        newName = fileName.substring(0, fileName.length - subLen) + RENAME_CONNECT_CHARACTER + renameCount;
317      }
318    }
319    return newName + suffix;
320  }
321
322  public static getFileNameReName(fileName: string): string[] {
323    if (StringUtil.isEmpty(fileName)) {
324      return null;
325    }
326    let index = fileName.lastIndexOf(RENAME_CONNECT_CHARACTER);
327    if (index === -1) {
328      return null;
329    }
330    let str = fileName.substring(index + 1, fileName.length);
331    let name = fileName.substring(0, index);
332    return [name, str];
333  }
334
335  public static getCurrentDir(path: string, isFolder: boolean): string {
336    if (isFolder) {
337      return path;
338    }
339    if (path) {
340      let index: number = path.lastIndexOf('/');
341      let len: number = path.length;
342      if (len > 1 && index > 1) {
343        return path.substring(0, index);
344      }
345    }
346    return path;
347  }
348
349  public static getUriPath(path: string): string {
350    if (path && FileUtil.isUriPath(path)) {
351      return path;
352    }
353    return null;
354  }
355
356  /**
357   * 根据文件的沙箱路径获取文件uri
358   * @param path 文件的沙箱路径
359   * @returns 文件的uri
360   */
361  public static getUriFromPath(path: string): string {
362    let uri = '';
363    try {
364      // 该接口如果以’/'结尾,返回的uri会以‘/'结尾
365      uri = FileUri.getUriFromPath(path);
366    } catch (error) {
367      Logger.e(TAG, 'getUriFromPath fail, error:' + JSON.stringify(error));
368    }
369    return uri;
370  }
371
372  /**
373   * 将文件uri转换成FileUri对象
374   */
375  public static getFileUriObjectFromUri(uri: string): FileUri.FileUri | undefined {
376    let fileUriObject: FileUri.FileUri | undefined;
377    try {
378      fileUriObject = new FileUri.FileUri(uri);
379    } catch (error) {
380      Logger.e(TAG, 'getFileUriObjectFromUri fail, error:' + JSON.stringify(error));
381    }
382    return fileUriObject;
383  }
384
385  /**
386   * 通过将文件uri转换成FileUri对象获取文件的沙箱路径
387   * @param uri 文件uri
388   * @returns 文件的沙箱路径
389   */
390  public static getPathFromUri(uri: string): string {
391    let path = '';
392    const fileUriObj = FileUtil.getFileUriObjectFromUri(uri);
393    if (!!fileUriObj) {
394      path = fileUriObj.path;
395    }
396    return path;
397  }
398
399  /**
400   * 创建文件夹
401   * @param parentFolderUri 父目录uri
402   * @param newFolderName 新文件夹名
403   * @returns 新文件夹uri
404   */
405  public static createFolderByFs(parentFolderUri: string, newFolderName: string): string {
406    try {
407      const parentFolderPath = FileUtil.getPathFromUri(parentFolderUri);
408      const newFolderPath = parentFolderPath + '/' + newFolderName;
409      fs.mkdirSync(newFolderPath);
410      return FileUtil.getUriFromPath(newFolderPath);
411    } catch (error) {
412      Logger.e(TAG, 'createFolderByFs fail, error:' + JSON.stringify(error));
413      throw error as Error;
414    }
415  }
416}