/** * 文件系统工具(框架 §8.3 / 附录 A.4)。封装 @kit.CoreFileKit fileIo + resourceManager。 * * 供 ResourceManager / AppDataInjector 使用:建目录、读写文本、递归删除、列目录、 * 把随包内置 rawfile(内置预置包 zip)拷贝到沙箱。纯原生内部 IO,H5 无感知。 */ import { fileIo as fs } from '@kit.CoreFileKit'; import { resourceManager } from '@kit.LocalizationKit'; import { Logger } from 'common'; export class FileSystem { private static readonly log: Logger = Logger.tag('FileSystem'); /** 路径是否存在。 */ static exists(path: string): boolean { try { return fs.accessSync(path); } catch (e) { const err = e as Error; FileSystem.log.w(`accessSync(${path}) failed: ${err.message}`); return false; } } /** 递归创建目录(已存在则忽略)。 */ static ensureDir(path: string): void { if (FileSystem.exists(path)) { return; } fs.mkdirSync(path, true); } /** 递归删除文件或目录(不存在/竞态则忽略,绝不抛错——对齐注释承诺)。 */ static rmrf(path: string): void { if (!FileSystem.exists(path)) { return; } try { const stat: fs.Stat = fs.statSync(path); if (stat.isDirectory()) { fs.rmdirSync(path); } else { fs.unlinkSync(path); } } catch (e) { const err = e as Error; FileSystem.log.w(`rmrf(${path}) ignored: ${err.message}`); } } /** 重命名/移动(同文件系统)。用于资源原子换入。 */ static rename(oldPath: string, newPath: string): void { fs.renameSync(oldPath, newPath); } /** 写文本(覆盖;自动建父目录)。 */ static writeText(path: string, content: string): void { FileSystem.ensureDir(FileSystem.dirOf(path)); const file: fs.File = fs.openSync(path, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE | fs.OpenMode.TRUNC); try { fs.writeSync(file.fd, content); } finally { fs.closeSync(file); } } /** 写二进制(覆盖;自动建父目录)。用于截图分享落盘等。 */ static writeBytes(path: string, bytes: Uint8Array): void { FileSystem.ensureDir(FileSystem.dirOf(path)); const file: fs.File = fs.openSync(path, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE | fs.OpenMode.TRUNC); try { // 按实际视图(byteOffset/byteLength)写入,避免底层 buffer 为大池子视图时写多余字节 const view: ArrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer; fs.writeSync(file.fd, view); } finally { fs.closeSync(file); } } /** 读文本(不存在返回空串)。 */ static readText(path: string): string { if (!FileSystem.exists(path)) { return ''; } return fs.readTextSync(path); } /** 列目录条目名(不存在返回空数组)。 */ static listDir(path: string): string[] { if (!FileSystem.exists(path)) { return []; } return fs.listFileSync(path); } /** 把随包内置 rawfile 拷贝到沙箱目标路径(用于内置预置包 zip)。 */ static copyRawFileTo(resMgr: resourceManager.ResourceManager, rawFilePath: string, destPath: string): void { const bytes: Uint8Array = resMgr.getRawFileContentSync(rawFilePath); FileSystem.ensureDir(FileSystem.dirOf(destPath)); const file: fs.File = fs.openSync(destPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE | fs.OpenMode.TRUNC); try { // 按 Uint8Array 的实际视图(byteOffset/byteLength)写入,避免底层 buffer 为大池子视图时写入多余字节致 zip 损坏 const view: ArrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer; fs.writeSync(file.fd, view); } finally { fs.closeSync(file); } } /** 取父目录路径(无分隔符则返回原串)。 */ static dirOf(path: string): string { const idx: number = path.lastIndexOf('/'); return idx > 0 ? path.substring(0, idx) : path; } }