M2(平台层): KvStore/FileSystem/HttpClient/Downloader/Unzipper/PermissionGuard/LocalUploadServer
T-M2-01 存储/文件:KvStore(preferences 持久化 urlpath/upurlpath)、FileSystem(fileIo 建删读写/列目录/拷贝内置 rawfile)
T-M2-02 网络/下载:HttpClient(GET 禁缓存,契约 §4.3)、Downloader(http 流式写盘+进度,原生异步不阻塞 UI)
T-M2-03 解压:Unzipper(zlib.decompressFile,原生异步)。偏差:下载/解压用原生异步 API 即满足"UI 不阻塞",
独立 TaskScheduler(TaskPool) 推迟到 M5 真有 CPU 密集任务(MD5)时再加,避免投机性死代码。
T-M2-04 权限/上传:PermissionGuard(用时申请,沙箱文件免存储权限)、LocalUploadServer(骨架,本机端口服务 M3 落地)
devecocli build 通过。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 文件系统工具(框架 §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;
|
||||
}
|
||||
const stat: fs.Stat = fs.statSync(path);
|
||||
if (stat.isDirectory()) {
|
||||
fs.rmdirSync(path);
|
||||
} else {
|
||||
fs.unlinkSync(path);
|
||||
}
|
||||
}
|
||||
|
||||
/** 写文本(覆盖;自动建父目录)。 */
|
||||
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 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 {
|
||||
// ArkTS:Uint8Array.buffer 是底层 ArrayBuffer,writeSync 接受 ArrayBuffer
|
||||
fs.writeSync(file.fd, bytes.buffer as ArrayBuffer);
|
||||
} finally {
|
||||
fs.closeSync(file);
|
||||
}
|
||||
}
|
||||
|
||||
/** 取父目录路径(无分隔符则返回原串)。 */
|
||||
static dirOf(path: string): string {
|
||||
const idx: number = path.lastIndexOf('/');
|
||||
return idx > 0 ? path.substring(0, idx) : path;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user