Skip to content

文件存储

鸿蒙文件存储 API:内部/外部存储、rawfile vs resource、沙箱机制。


1. 存储目录结构

应用沙箱(Sandbox)
├── /data/storage/el2/base/com.example.app/
│   ├── files/            # 应用私有文件
│   ├── cache/            # 缓存目录
│   ├── rdb/              # 数据库文件
│   └── preferences/      # Preferences 文件

外部存储(公共目录)
├── /storage/media/0/
│   ├── Documents/
│   ├── Download/
│   ├── Pictures/
│   ├── DCIM/(相机)
│   └── Music/

2. 内部存储

2.1 读取内部文件

typescript
import fs from '@ohos.file.fs';

// 获取内部文件目录
let filesDir = context.filesDir;  // /data/storage/el2/base/com.example.app/files
let cacheDir = context.cacheDir;  // /data/storage/el2/base/com.example.app/cache

// 写文件
let fileStr = fs.openSync('test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
let msg = 'Hello HarmonyOS';
fs.writeSync(fileStr, new TextEncoder().encode(msg));
fs.closeSync(fileStr);

// 读文件
let fileStr2 = fs.openSync('test.txt', fs.OpenMode.READ_ONLY);
let fileStat = fs.lstatSync(fileStr2);
let buffer = new Uint8Array(fileStat.size);
fs.readSync(fileStr2, buffer, { buffer });
let content = new TextDecoder().decode(buffer);
fs.closeSync(fileStr2);

2.2 目录操作

typescript
// 获取应用目录
let appDir = context.filesDir;
let cacheDir = context.cacheDir;

// 创建子目录
fs.mkdirSync(`${appDir}/subdir`);

// 列出目录内容
let files = fs.readdirSync(appDir);
for (let file of files) {
    console.log('文件:', file);
}

// 删除文件
fs.unlinkSync(`${appDir}/test.txt`);

// 删除目录
fs.rmdirSync(`${appDir}/subdir`);

3. rawfile vs resource

维度rawfileresource
访问方式文件名字符串$r 引用
编译原始文件,不编译编译后的资源
多语言❌ 不支持✅ 自动适配
多设备❌ 不支持✅ 自动适配
推荐大文件/二进制图片/字符串/配置
typescript
// rawfile(原始文件)
let fd = fs.openSync('rawfile://config.json', fs.OpenMode.READ_ONLY);
let content = fs.readSync(fd, fs.readFileStatSync(fd).size);
fs.closeSync(fd);
let data = JSON.parse(new TextDecoder().decode(content));

// resource(编译资源,推荐)
let str = $r('app.string.hello');
let img = $r('app.media.icon');

4. 文件 URI

4.1 获取相册图片 URI

typescript
// 使用 PhotoViewPicker 选择图片
import photoView from '@ohos.multimedia.photoView';

let picker = new photoView.PhotoViewPicker();
let viewList = picker.select({
    maxSelectCount: 1,
    mimeType: photoView.PhotoViewMimeType.JPEG
});

// URI 转 File
let uri = viewList[0].uri;
let fileFd = fs.openSync(uri, fs.OpenMode.READ_ONLY);

4.2 URI 注意事项

⚠️ 用户文件 URI 是临时的!
├─ 需要长期访问 → 复制到应用沙箱
├─ 不能直接当文件路径用
└─ 用完及时关闭 FileDescriptor

5. 外部存储

5.1 请求存储权限

json5
// module.json5
"reqPermissions": [
  {
    "name": "ohos.permission.INTERNET"
  },
  {
    "name": "ohap.permission.READ_MEDIA"
  }
]

5.2 访问公共目录

typescript
import mediaLibrary from '@ohos.multimedia.mediaLibrary';

// 获取媒体库
let context = getContext(this);
let mediaSel = new mediaLibrary.MediaSession();
let photos = mediaSel.getPhotos();

// 遍历照片
let iter = photos.getPhotoIterator();
while (iter.hasNext()) {
    let photo = iter.next();
    console.log('照片 URI:', photo.uri);
}

6. 面试高频考点

Q1: rawfile 和 resource 的区别?

回答:rawfile 是原始文件,需手动读流;resource 是编译后的资源,通过 $r 引用,支持多语言/多设备自动适配。

Q2: 用户文件 URI 注意事项?

回答:URI 是临时的,需要长期访问时复制到应用沙箱,不能直接当文件路径使用。


🐱 小猫提示:文件存储记住 "rawfile 原始文件、resource 编译资源、URI 临时、复制沙箱长期用"