查看: 5266|回复: 3

鸿蒙 ASCF 文件 API 避坑:internal 路径与编

[复制链接]
发表于 2026-9-17 11:00:00 | 显示全部楼层 |阅读模式
文件操作是鸿蒙元服务开发绕不开的一环:缓存数据、保存图片、读取配置、解压文件都会用到。ASCF 的文件能力通过 has.getFileSystemManager() 暴露为 FileSystemManager,且是全局唯一单例,设计上与 RecorderManager、BackgroundAudioManager 类似。使用前先记两条硬规则:所有文件 API 的路径只支持 internal:// 开头的沙箱路径,不支持外部存储路径;相册等外部路径不能直接操作,通常要先 copyFile 到沙箱。

一、获取实例与路径规则
  1. const fs = has.getFileSystemManager();
复制代码
路径只支持 internal://,这是后续所有读写、目录、解压操作的前提。

二、基础文件读写
写文件最常用的是 writeFile,data 支持 string 和 ArrayBuffer。写字符串可直接指定 encoding:
  1. const fs = has.getFileSystemManager();
  2. fs.writeFile({
  3.   filePath: 'internal://cache/data.txt',
  4.   data: 'Hello World',
  5.   encoding: 'utf-8',
  6.   success: () => {
  7.     console.info('写入成功');
  8.   },
  9.   fail: (err) => {
  10.     console.error('写入失败:', err);
  11.   }
  12. });
复制代码
同步写法用 writeFileSync。读文件用 readFile:传 encoding: 'utf-8' 返回字符串;不传 encoding 返回 ArrayBuffer。删除文件用 unlink;检查存在用 access;拷贝用 copyFile;重命名用 rename。
  1. fs.readFile({
  2.   filePath: 'internal://cache/data.txt',
  3.   encoding: 'utf-8',
  4.   position: 0,
  5.   success: (res) => {
  6.     console.info('文件内容:', res.data);
  7.   },
  8.   fail: (err) => {
  9.     console.error('读取失败:', err);
  10.   }
  11. });
  12. fs.unlink({
  13.   filePath: 'internal://cache/data.txt',
  14.   success: () => {
  15.     console.info('删除成功');
  16.   }
  17. });
  18. fs.copyFile({
  19.   srcPath: 'internal://cache/temp.txt',
  20.   destPath: 'internal://files/saved.txt',
  21.   success: () => {
  22.     console.info('拷贝成功');
  23.   }
  24. });
复制代码
追加写入用 appendFile,适合日志,不用先读再拼接:
  1. fs.appendFile({
  2.   filePath: 'internal://cache/log.txt',
  3.   data: '新的一行\n',
  4.   encoding: 'utf-8',
  5.   success: () => {
  6.     console.info('追加成功');
  7.   }
  8. });
复制代码
截断文件用 truncate,length 指定保留的字节数。

三、目录与文件信息
创建目录用 mkdir,recursive: true 可递归创建中间目录,类似 mkdir -p;读取目录用 readdir,返回 res.files;删除目录用 rmdir,recursive: true 会删除目录下所有文件和子目录。
  1. fs.mkdir({
  2.   dirPath: 'internal://cache/mydir',
  3.   recursive: true,
  4.   success: () => {
  5.     console.info('目录创建成功');
  6.   }
  7. });
  8. fs.readdir({
  9.   dirPath: 'internal://cache/',
  10.   success: (res) => {
  11.     console.info('目录内容:', res.files);
  12.   }
  13. });
复制代码
获取文件大小用 getFileInfo,获取文件状态用 stat,Stats 对象提供 isFile() 和 isDirectory()。getSavedFileList 只列出通过 saveFile 保存的文件,包含 filePath、size、createTime,不包括 writeFile 创建的文件;要列出所有文件应使用 readdir。

四、高级 fd 读写、解压与文档预览
如果要精确控制读写位置或处理大文件,可以用文件描述符方式:openSync 打开,readSync 读取,writeSync 写入,closeSync 关闭。示例中 flag 使用 'r+' 表示读写模式。
  1. const fs = has.getFileSystemManager();
  2. const fd = fs.openSync({
  3.   filePath: 'internal://cache/data.bin',
  4.   flag: 'r+'
  5. });
  6. const readResult = fs.readSync({
  7.   fd: fd,
  8.   arrayBuffer: new ArrayBuffer(1024),
  9.   length: 1024
  10. });
  11. console.info('读取了', readResult.bytesRead, '字节');
  12. fs.writeSync({
  13.   fd: fd,
  14.   data: '写入的数据',
  15.   encoding: 'utf-8'
  16. });
  17. fs.closeSync({ fd: fd });
复制代码
解压用 unzip,只支持 zip 格式,不支持 tar.gz、rar 等;has.openDocument 可调起系统预览器打开文档,支持 pdf、doc、docx、xls、xlsx、ppt、pptx。

五、典型场景
缓存 JSON:写入用 writeFile,读取用 readFileSync,并处理解析异常。
日志追加:用 appendFile 写入时间戳和消息。
保存 chooseFile 文件:chooseFile 返回的临时路径不能直接读写,需要先 copyFile 到 internal://files/ 下的沙箱持久化目录。
  1. has.chooseFile({
  2.   type: 'file',
  3.   count: 1,
  4.   success: (res) => {
  5.     const file = res.tempFiles[0];
  6.     const fs = has.getFileSystemManager();
  7.     const destPath = `internal://files/${file.name}`;
  8.     fs.copyFile({
  9.       srcPath: file.path,
  10.       destPath: destPath,
  11.       success: () => {
  12.         console.info('文件已保存:', destPath);
  13.       }
  14.     });
  15.   }
  16. });
复制代码

六、踩坑清单
1. 路径只支持 internal://,外部路径如相册路径不能直接操作,需要先 copyFile 到沙箱。
2. writeFile 默认覆盖写入,不是追加;要追加用 appendFile。
3. readFile 不传 encoding 时 res.data 是 ArrayBuffer,不是字符串;需要字符串就传 encoding: 'utf-8'。
4. 写图片、音频等二进制数据时,data 要传 ArrayBuffer,且不要传 encoding。
5. getSavedFileList 只列出 saveFile 保存的文件,不包括 writeFile 创建的文件;列出所有文件用 readdir。
6. 删文件用 unlink,删目录用 rmdir,搞反会报错。
7. unzip 只支持 zip,不支持 tar.gz、rar 等格式。

从使用频率看,日常开发最常用的是 writeFile、readFile、appendFile、unlink、copyFile、mkdir、readdir。如果只是存简单 key-value 数据,用 has.setStorage / has.getStorage 就够了,不必折腾文件 API;文件 API 更适合存大数据、二进制文件、日志这类场景。把 internal:// 路径限制、readFile 的 encoding 行为、writeFile 与 appendFile 的区别记住,基本就能避开主要问题。
回复

使用道具 举报

发表于 2026-9-17 19:00:00 | 显示全部楼层

Re: 鸿蒙 ASCF 文件 API 避坑:internal 路径与编

整理得挺全面,尤其 internal:// 沙箱路径这条很关键,外部路径不能直接操作、相册文件要先 copyFile 到沙箱,确实容易踩坑。基础读写、追加日志、递归建目录、rmdir recursive 这些示例也很直观,fd 读写对处理大文件或精确位置挺有参考价值。最后 chooseFile 保存到 internal: 那段好像没写完,const file = res.tempFiles[0]; 后面就断了,方便的话可以补一下后续 copyFile 和持久化处理的完整流程。另外 getSavedFileList 只列 saveFile 保存的文件、不包括 writeFile 创建的,这个提醒很实用。感谢分享,收藏了。
回复 支持 反对

使用道具 举报

发表于 2026-9-17 19:10:00 | 显示全部楼层

Re: 鸿蒙 ASCF 文件 API 避坑:internal 路径与编

帖子写得很实在,路径规则和 API 清单基本覆盖了日常用得到的部分,尤其是 getSavedFileList 那条,确实容易踩——很多人以为它能列出沙箱里所有文件,结果 writeFile 写进去的怎么都查不到,排查半天。 补充几个我实际踩过的坑: 一是 cache 和 files 的区分。internal: 属于缓存目录,系统在空间紧张时会主动清理,只适合放临时数据;要持久保存的图片、配置、下载文件建议放 internal: 被清之后再用 readFile 读会直接 fail,所以读的地方最好都兜一下 fail 分支。 二是 readFile 忘了传 encoding。不传返回的是 ArrayBuffer,读文本会拿到一串字节,如果代码里还顺手做了字符串拼接或者 JSON.parse,报错信息看着毫不相关。同理 readFileSync 解 JSON 一定要包 try/catch,元服务里异常抛出来体验很差。 三是大文件不要用同步接口。readFileSync、writeFileSync 在主线程上跑,文件稍大就卡界面,几百 KB 以上建议走 fd 分片读,配合 position 控制偏移,或者干脆用异步版本。示例里 openSync 的 flag 用 r+ 有个前提,文件必须已存在,想在打开时自动创建得用 a+ 或先 access 判断一下。 四是 unzip 只吃 zip,后
回复 支持 反对

使用道具 举报

发表于 2026-9-17 19:20:00 | 显示全部楼层

Re: 鸿蒙 ASCF 文件 API 避坑:internal 路径与编

感谢楼主整理,这份避坑很实用。internal:// 沙箱路径这条确实容易踩,外部路径不能直接操作、要先 copyFile 到沙箱,这个点很关键。读写、追加、截断、目录、fd、解压和文档预览都覆盖到了,尤其是 getSavedFileList 只列 saveFile 保存的文件,不包括 writeFile 创建的,还有 unzip 只支持 zip,这两个细节很容易搞混。chooseFile 返回的临时路径不能直接读写,要先 copyFile 到 internal: 持久化,也很提醒人。想问下 appendFile 写日志时,如果文件不存在会自动创建吗,还是需要先 writeFile?整体写得很清楚,收藏了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-7 02:21 , Processed in 0.027645 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部