系列:HarmonyOS 开发入门 · 13
做"选择 PDF""导入文件""导出 JSON"时,很多新手第一反应是找系统真实路径。
HarmonyOS 里更应该围绕 URI + 文件 API + 应用沙箱 来理解。
1. 选择文档用 DocumentViewPicker
导入:
ts
import { picker } from '@kit.CoreFileKit'
创建选择器:
ts
const documentPicker = new picker.DocumentViewPicker()
选择文件:
ts
async function selectDocument(): Promise<string | undefined> {
const options = new picker.DocumentSelectOptions()
options.maxSelectNumber = 1
const documentPicker = new picker.DocumentViewPicker()
const result = await documentPicker.select(options)
return result.length > 0 ? result[0] : undefined
}
不同 SDK 版本可配置的文件类型筛选字段可能不同,按当前接口定义设置即可。
2. 返回值是文档 URI
例如可能是这种语义:
text
file://docs/storage/Users/currentUser/Download/test.pdf
不要依赖 URI 字符串的内部片段写业务逻辑。
系统文档也明确不建议开发者自己解析 URI 片段。
3. 读取文件
拿到 URI 后,可以使用文件管理能力打开。
ts
import { fileIo } from '@kit.CoreFileKit'
function readFile(uri: string): Uint8Array {
const file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY)
try {
const stat = fileIo.statSync(file.fd)
const buffer = new ArrayBuffer(stat.size)
fileIo.readSync(file.fd, buffer)
return new Uint8Array(buffer)
} finally {
fileIo.closeSync(file)
}
}
大文件不要一次性全部读进内存,这段更适合入门小文件示例。
4. 应用沙箱目录要分清
常用 Context 目录大致有:
text
filesDir
cacheDir
databaseDir
filesDir
应用长期管理的普通文件。
cacheDir
缓存,可被清理,不要放唯一的重要数据。
databaseDir
数据库相关目录。
5. 一个"导入文件"的正确思路
如果用户选择一个文件后,应用后面还要长期使用,我通常会考虑:
text
DocumentViewPicker
↓
拿到 URI
↓
读取
↓
复制一份到应用 filesDir
↓
记录自己的文件元数据
这样后续业务更可控。
当然,如果业务只需要即时读取,就没必要每次都复制。
6. 导出文件可以用 save
DocumentViewPicker 不只是选择,还提供保存语义。
比如用户点"导出备份",让用户自己选保存位置,再把内容写到返回 URI。
这种体验比偷偷往某个固定目录写文件更符合用户预期。
7. 不要用同步 IO 处理大文件
上面的 openSync/readSync 很适合解释 API,但真实项目处理几十 MB、几百 MB 文件时,不应该长期阻塞 UI 线程。
需要考虑:
- 异步 IO;
- 分块读写;
- TaskPool;
- 进度回调;
- 取消任务。
文件越大,这些越重要。
8. 图片 URI 和文档 URI 不要混为一谈
媒体文件通常由 Media Library Kit 管理;普通文档更多通过文件 Picker 管理。
两个 URI 体系的获取和后续处理能力并不完全相同。
所以不要写一个 getRealPath(uri) 企图处理所有文件类型------移动系统里这种思路通常会把自己带进坑里。
总结
文件处理最核心的认知:
Picker 给你 URI,应用通过系统文件能力访问,不要执着于"真实绝对路径"。
下一篇进入 UI 交互:AlertDialog、CustomDialog,以及项目里到底什么时候该用系统弹窗、什么时候做自定义弹层。