应用沙箱与文件目录

鸿蒙每个应用都有独立的文件沙箱,只能读写自己沙箱内的文件,碰不到别的应用。这套隔离让恶意应用拿不到你的相册、文档,也让卸载应用时数据能干净地一起清掉。

沙箱是安全边界:应用内部随便放,跨边界必须走系统能力。

沙箱内按用途分成几个目录:应用数据目录存数据库和配置,缓存目录存临时文件,文件管理目录存用户可感知的文件。选对目录,卸载清理、备份恢复都有章可循。

刚接触鸿蒙文件开发的同学最容易犯的错,是拿路径当普通 Linux 路径直接用。沙箱路径每个应用都不一样,而且由系统分配,不能写死。正确的做法是运行时通过接口拿到自己的沙箱根,再在根上拼子路径。记住这一点,后面的代码就不会跑偏。

沙箱路径与 URI

获取应用沙箱根目录用 context 的 filesDir、cacheDir,或者通过文件管理接口拿沙箱路径。拿到的是 file:// 形式的 URI,转成普通路径就能配合文件系统接口使用。

import { common } from '@kit.AbilityKit';
import { fileIo } from '@kit.CoreFileKit';

const ctx = getContext(this) as common.UIAbilityContext;
const sandboxDir = ctx.filesDir; // /data/storage/el2/base/haps/entry/files
const cacheDir = ctx.cacheDir;   // /data/storage/el2/base/haps/entry/cache

const fileUri = fileIo.openSync(sandboxDir + '/notes.txt', fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
沙箱目录速查
  • filesDir正式数据,随备份走。
  • cacheDir临时文件,系统可清。
  • 沙箱根不同应用不同,别写死。

文件读写实战

读写文件用 fileIo 的 openSync、writeSync、readSync,或者更省事的文件流接口。写文本注意编码,读回来同样按 UTF-8 解码,避免中文乱码。

import { fileIo } from '@kit.CoreFileKit';

const file = fileIo.openSync(sandboxDir + '/diary.txt',
  fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
fileIo.writeSync(file.fd, '今天学了鸿蒙文件系统');
fileIo.fsyncSync(file.fd);
fileIo.closeSync(file);

const f2 = fileIo.openSync(sandboxDir + '/diary.txt', fileIo.OpenMode.READ_ONLY);
const buf = new ArrayBuffer(4096);
const n = fileIo.readSync(f2.fd, buf);
const bytes = new Uint8Array(buf.slice(0, n));
let text = '';
for (let i = 0; i < bytes.length; i++) text += String.fromCharCode(bytes[i]);
console.log('读到的内容', text);
fileIo.closeSync(f2);

写入后调用 fsync 把数据真正落到磁盘,防止系统掉电丢数据。小文件读写用同步接口简单直接;大文件用流式分段读写,避免一次性把整个文件装进内存。

图片与媒体文件存取

应用自己的图片可以放沙箱文件目录,用户想保存到相册,就要走 PhotoAccessHelper 或 FilePicker 交给系统,别自己往系统目录硬写。

鸿蒙文件存储:多本发光数据卡片与数据库表节点整齐存进带锁存储柜、柜门发光锁孔的蓝调插画
数据放进带锁的沙箱,安全又整洁。

FilePicker 的 DocumentViewPicker 可以把文件保存到用户选定的位置,用户全程可见、可撤销,符合系统对用户文件的保护要求。选完返回的文件 URI 保存在沙箱里,下次用再通过 URI 打开。