杨利杰YJlio博客头图

本地文件与应用沙箱

大家好,我是杨利杰 YJlio。

上一节使用Preferences保存简单设置。这一节我把关注点转到文件:目录从哪里取得,应用可以访问什么范围,打开的文件如何关闭。

本篇编号026,计划日期2026年10月16日。原稿已保留。原稿的describeResult只处理显示文字,不包含文件访问;下方补充文件操作学习示例,尚未在本机编译或设备运行。图片均为概念示意。

一、先读写应用自己的练习文件

本例只操作应用文件目录中的note26.txt,不访问相册、下载目录或其他应用数据。先把自己的文件路径、内容与失败反馈核对清楚,再学习用户文件选择和授权。

沙箱限制应用可见的目录范围。应用自己的文件访问与用户文件访问是不同路径,不能通过拼接一个看起来像系统目录的字符串绕过访问边界。

从应用自己的目录开始

二、按文件用途选择目录

Context属性本篇关注的用途
filesDir普通应用文件,本例保存练习文本
cacheDir可重新生成的缓存,可能被清理
tempDir临时处理文件,不承担长期保留任务
preferencesDir首选项相关文件,按Preferences接口管理

本例选择filesDir。缓存不适合存放唯一的重要数据;普通文件目录也不是永久备份。生命周期和访问条件可参见官方应用沙箱目录说明。

按用途选择文件目录

三、用Context取得路径,不写死设备目录

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

function demoPath(context: common.UIAbilityContext): string {
  return `${context.filesDir}/note26.txt`;
}

context应来自当前可用的UIAbility或页面宿主。函数参数不是路径字符串,也不是自己构造的空对象。本例使用UIAbilityContext对应的目录,不把它与ApplicationContext目录混为一谈。

拼接的是自己约定的固定文件名note26.txt,不接受用户提供的任意路径。调试工具看到的物理路径与应用看到的沙箱路径可能不同,所以不要把调试输出的物理根路径硬编码到业务代码。

目录由Context取得,文件名由本例固定,设备上的物理路径不写死。

用Context取得filesDir

四、写入前看清打开方式

async function writeDemo(context: common.UIAbilityContext): Promise<void> {
  const path = demoPath(context);
  const file = await fileIo.open(path,
    fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE | fileIo.OpenMode.TRUNC);
  try {
    const text = 'Hello HarmonyOS';
    const written = await fileIo.write(file.fd, text);
    if (written !== text.length) {
      throw new Error('练习文本未完整写入');
    }
  } finally {
    await fileIo.close(file.fd);
  }
}

CREATE让不存在的文件被创建;TRUNC在以写权限打开已有文件时把长度裁剪为零。本例每次写入都会替换练习文件的旧内容,不是追加。

written的单位是字节。这里固定为ASCII文本Hello HarmonyOS,每个字符对应一个UTF-8字节,才可与text.length比较。改成中文等内容时,要按编码后的字节长度处理,不能沿用这条比较。

TRUNC会清空已有内容;这段示例只用于可覆盖的note26.txt练习文件。

这不是原子更新或备份方案。中途写入失败可能留下空文件或不完整内容,不能用于直接覆盖重要用户文档。

写入演示文件会覆盖旧内容

五、读取文件,再整理显示结果

function describeResult(input: string): string {
  return input.trim().length === 0 ? '暂无内容' : `已读取:${input}`;
}

async function readDemo(context: common.UIAbilityContext): Promise<string> {
  const input = await fileIo.readText(demoPath(context));
  return describeResult(input);
}

readText负责读取UTF-8文本;describeResult保留原稿的逻辑,只负责显示。全空白文本显示暂无内容,非空内容显示已读取前缀。前缀不代表函数自身完成了任何IO,实际读取发生在readDemo中。

文件不存在、无法访问或读取失败时,Promise会失败,调用方需要处理。不能将读取失败直接改写成暂无内容,这会掩盖真实原因。

读文本,再生成显示文字

六、打开成功后,用finally关闭

writeDemo在open成功之后进入try,因此写入或完整性检查失败也会经过finally。readText自行处理其内部文件访问,本例没有为它额外打开文件句柄。

页面调用可以按以下顺序记录结果:

import { BusinessError } from '@kit.BasicServicesKit';

async function runDemo(context: common.UIAbilityContext): Promise<string> {
  try {
    await writeDemo(context);
    return await readDemo(context);
  } catch (error) {
    const err = error as BusinessError;
    console.error(`file demo failed: ${err.code}, ${err.message}`);
    return '文件操作失败,请检查日志';
  }
}

本例的普通Error不一定有平台错误码,日志中应同时查看message;不要凭空补写错误编号。close自身也可能失败,实际排查需保留写入与关闭阶段的错误,不能只看最后一行。

上述代码块属于一组函数,应放在同一练习文件中组织使用;导入语句不要重复添加。页面获得可用上下文后调用runDemo,并把返回文字赋给观察状态。本文没有提供完整页面、文件选择器或后台任务。

打开的文件必须关闭

七、应用文件与用户文档分别处理

自己的filesDir路径,不等于用户从文件选择器选择的URI。用户文件应按相应选择、授权与文件访问接口处理,不能把URI未经处理当作普通路径拼接。

本例没有实现用户文件访问,也没有读取其他应用的文件。清除应用数据、卸载相关包、切换上下文或环境,都可能改变原来的文件条件,不应承诺“保存后永远存在”。

先确认路径属于哪个上下文、哪类文件,再决定用哪套访问方式。

沙箱文件不是用户文档

八、按路径、内容和失败记录核验

操作预期或需记录内容当前状态
取得demoPath记录实际filesDir与note26.txt待验证
写入练习文本固定内容Hello HarmonyOS待验证
读取文本预期已读取:Hello HarmonyOS待验证
单独检查空白显示describeResult对空白返回暂无内容待验证
文件操作失败显示失败并保留日志待验证
正常重启后只调用readDemo核对原文件仍在与内容,避免先写再读掩盖结果待验证

记录实际DevEco Studio、SDK/API、设备和操作顺序。第一次先写后读;若核对重启后的保留情况,则只读取,不能再次调用会覆盖文件的runDemo。

代码使用CoreFileKit的Promise形式,接口已参考官方基础文件IO文档,仍需在当前SDK中编译与适配。readText整段读取适用于本例的小文本,不扩展为大文件处理方案。

核对路径、内容与失败

写在最后

这一节我把“文件访问”与“结果显示”拆开了:Context确定目录,固定文件名确定目标,open和write负责写入,readText负责读取,describeResult只处理展示。

最需要记住的是覆盖方式与资源关闭。下一篇学习关系型数据库,再区分一段文本文件与多条业务记录的存储需求。

参考资料

  1. OpenHarmony官方文档:应用沙箱目录,用于核对目录用途与路径边界。
  2. OpenHarmony官方文档:基础文件IO接口,用于核对open、write、close、readText与打开模式。实际HarmonyOS工程以对应SDK文档为准。
  3. 本系列第026篇原稿:《本地文件与应用沙箱初识》,计划日期2026-10-16。

声明:本文为个人学习笔记。代码和配图用于说明应用文件操作,尚未执行SDK编译或设备实测;写入、读取与重启结果均为待验证内容。

结束分隔线

返回顶部

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐