《HarmonyOS技术精讲-Core File Kit》第3篇:文件读写——从文本到二进制数据
文件读写从文本到二进制数据HarmonyOS NEXT 开发里文件读写这个 API 经常被误用。很多人第一次接触 Core File Kit 时会发现官方示例能运行但实际项目里总会出现各种意外——要么文件路径不对要么写进去的内容读不出来要么读取大文件直接卡死。这个功能本身不复杂但真正麻烦的是沙箱路径的理解和流式读取的处理。这篇文章会从文本和二进制数据两个场景入手把标准操作和常见问题一次说清楚。Core File Kit 解决了什么问题在 HarmonyOS 应用开发中所有文件操作都基于沙箱机制。应用无法随意访问系统目录只能操作自己的沙箱目录下的文件。Core File Kit 提供了统一的文件读写能力底层封装了沙箱路径解析和文件描述符管理。跟直接用fs模块相比Core File Kit 的几个关键差异能力fs 模块Core File Kit沙箱路径需手动拼接自动解析流式读取需手动创建流内置流式接口二进制支持需 ArrayBuffer直接支持异步异常处理基础更完善实际开发中推荐优先使用 Core File Kit 提供的高阶 API特别是fileManager.readText和writeText这类封装好的方法能减少不少错误处理代码。环境说明DevEco Studio 版本DevEco Studio 6.1.0 及以上 HarmonyOS SDK 版本HarmonyOS 6.1.0(23) 及以上 目标设备手机核心实现文本读写先从最常见的文本文件开始。这段代码用于向沙箱目录写入一段文本然后读取并打印出来。// TextRW.etsimport{fileManager}fromkit.CoreFileKit;import{common}fromkit.AbilityKit;exportclassTextRW{privatecontext:common.Context;constructor(context:common.Context){this.contextcontext;}// 写入文本文件asyncwriteText(fileName:string,content:string):Promisevoid{try{// 获取沙箱目录路径constsandboxPaththis.context.cacheDir;constfilePathsandboxPath/fileName;// 写入文本自动创建文件如果不存在awaitfileManager.writeText(filePath,content);console.info(写入成功:${filePath});}catch(error){console.error(写入失败:${error.code},${error.message});throwerror;}}// 读取文本文件asyncreadText(fileName:string):Promisestring{try{constsandboxPaththis.context.cacheDir;constfilePathsandboxPath/fileName;// 读取文本constcontentawaitfileManager.readText(filePath);console.info(读取内容:${content});returncontent;}catch(error){console.error(读取失败:${error.code},${error.message});throwerror;}}}注意事项writeText会覆盖文件内容如果文件不存在则自动创建readText要求文件必须存在否则会抛出错误沙箱路径建议使用cacheDir或tempDir避免持久化数据累积核心实现二进制数据读写实际项目中文件读写不仅是文本更多时候是图片、音频等二进制数据。// BinaryRW.etsimport{fileManager}fromkit.CoreFileKit;import{common}fromkit.AbilityKit;exportclassBinaryRW{privatecontext:common.Context;constructor(context:common.Context){this.contextcontext;}// 写入二进制数据如图片字节asyncwriteArrayBuffer(fileName:string,buffer:ArrayBuffer):Promisevoid{try{constsandboxPaththis.context.cacheDir;constfilePathsandboxPath/fileName;// 写入二进制数据awaitfileManager.writeArrayBuffer(filePath,buffer);console.info(二进制写入成功:${filePath});}catch(error){console.error(二进制写入失败:${error.code},${error.message});throwerror;}}// 读取二进制数据并验证asyncreadAndVerifyArrayBuffer(fileName:string,originalBuffer:ArrayBuffer):Promiseboolean{try{constsandboxPaththis.context.cacheDir;constfilePathsandboxPath/fileName;// 读取二进制数据constreadBufferawaitfileManager.readArrayBuffer(filePath);// 验证数据一致性constoriginalViewnewUint8Array(originalBuffer);constreadViewnewUint8Array(readBuffer);if(originalView.length!readView.length){console.warn(数据长度不一致);returnfalse;}for(leti0;ioriginalView.length;i){if(originalView[i]!readView[i]){console.warn(数据不一致: 位置${i});returnfalse;}}console.info(数据验证通过);returntrue;}catch(error){console.error(读取验证失败:${error.code},${error.message});returnfalse;}}}为什么这样写更稳定使用ArrayBuffer而不是Uint8Array作为参数因为writeArrayBuffer和readArrayBuffer原生支持ArrayBuffer验证环节使用Uint8Array逐字节比较避免引用比较陷阱异步回调里处理所有异常防止未捕获错误导致崩溃核心实现流式读取大文件对于大文件一次性读取会撑爆内存。Core File Kit 提供了流式接口// StreamRW.etsimport{fileManager}fromkit.CoreFileKit;import{common}fromkit.AbilityKit;exportclassStreamRW{privatecontext:common.Context;constructor(context:common.Context){this.contextcontext;}// 流式写入大文件asyncwriteLargeFile(fileName:string,data:ArrayBuffer):Promisevoid{try{constsandboxPaththis.context.cacheDir;constfilePathsandboxPath/fileName;// 创建可写流conststreamawaitfileManager.createWriteStream(filePath);// 分段写入constchunkSize1024*1024;// 1MBletoffset0;while(offsetdata.byteLength){constendMath.min(offsetchunkSize,data.byteLength);constchunkdata.slice(offset,end);awaitstream.write(chunk);offsetend;}// 关闭流awaitstream.close();console.info(流式写入完成);}catch(error){console.error(流式写入失败:${error.code},${error.message});throwerror;}}// 流式读取大文件asyncreadLargeFile(fileName:string,onChunk:(chunk:ArrayBuffer)void):Promisevoid{try{constsandboxPaththis.context.cacheDir;constfilePathsandboxPath/fileName;// 创建可读流conststreamawaitfileManager.createReadStream(filePath);// 分段读取constchunkSize1024*1024;// 1MBletreadBuffer:ArrayBuffer;do{readBufferawaitstream.read(chunkSize);if(readBuffer.byteLength0){onChunk(readBuffer);}}while(readBuffer.byteLength0);// 关闭流awaitstream.close();console.info(流式读取完成);}catch(error){console.error(流式读取失败:${error.code},${error.message});throwerror;}}}流式读写要点createWriteStream返回的流会自动处理文件创建和写入read方法返回的ArrayBuffer长度可能小于请求的大小这是正常行为必须手动调用close()释放资源否则会触发系统警告常见问题 1沙箱路径错误现象写入文件后在指定路径找不到文件或读取时报错 “No such file or directory”。原因开发者混用了this.context.filesDir和this.context.cacheDir或者手动拼接路径时用了错误的根目录。解决方案// 错误方式constwrongPath/data/storage/el2/base/haps/entry/cache/file.txt;// 正确方式constcorrectPaththis.context.cacheDir/file.txt;常见问题 2读取大文件导致 OOM现象读取超过 100MB 的文件时应用直接闪退。原因使用了readArrayBuffer一次性读取整个文件内存撑爆。解决方案改用流式读取分段处理。如果确实需要全部数据可以// 分段拼接constchunks:ArrayBuffer[][];conststreamawaitfileManager.createReadStream(filePath);letchunk:ArrayBuffer;while((chunkawaitstream.read(1024*1024)).byteLength0){chunks.push(chunk);}awaitstream.close();// 合并consttotalLengthchunks.reduce((sum,c)sumc.byteLength,0);constfullBuffernewArrayBuffer(totalLength);constfullViewnewUint8Array(fullBuffer);letoffset0;for(constcofchunks){fullView.set(newUint8Array(c),offset);offsetc.byteLength;}最佳实践统一管理文件路径不要到处写路径拼接封装一个工具类集中管理沙箱路径避免路径错误散落在各个模块中。优先使用流式接口即使当前文件不大也要养成用流的习惯。线上用户上传的文件大小不可控流式接口是防 OOM 的第一道防线。写后立即读校验特别是二进制数据写入后建议立即读取并逐字节校验防止写入过程中因为系统异常导致数据损坏。这点在处理图片、配置文件时尤其重要。Demo 入口// Index.etsimport{TextRW}from./TextRW;import{BinaryRW}from./BinaryRW;import{common}fromkit.AbilityKit;EntryComponentstruct Index{build(){Row(){Column(){Button(写入文本).onClick(async(){constcontextgetContext(this)ascommon.Context;consttextRWnewTextRW(context);awaittextRW.writeText(test.txt,Hello HarmonyOS);constcontentawaittextRW.readText(test.txt);console.info(读取结果: content);})Button(写入二进制).onClick(async(){constcontextgetContext(this)ascommon.Context;constbinaryRWnewBinaryRW(context);constbuffernewArrayBuffer(1024);constviewnewUint8Array(buffer);view.fill(0x41);// 填充 AawaitbinaryRW.writeArrayBuffer(test.bin,buffer);constresultawaitbinaryRW.readAndVerifyArrayBuffer(test.bin,buffer);console.info(验证结果: result);})}.width(100%)}.height(100%)}}FAQQ为什么写入后立即读取会返回空字符串A检查是否在写入完成前就开始读取。writeText和readText都是异步操作必须await确保顺序执行。Q读取文件时为什么有时候能读到内容有时候读不到A最常见原因是文件路径写死了没有根据沙箱环境动态获取。建议每次都通过this.context.cacheDir拼接路径而不是硬编码。QwriteArrayBuffer写入后读取的 ArrayBuffer 大小不一致A检查是否在写入过程中有其他线程修改了文件或者磁盘空间不足导致写入不完整。建议在写入后立即读取校验。示例代码地址项目地址

相关新闻

2026年南京改灯:老师傅丰富经验背后的改灯要点解析

2026年南京改灯:老师傅丰富经验背后的改灯要点解析

开头:技术痛点/趋势引入2026年,随着汽车行业的蓬勃发展,改灯 领域面临新的挑战。在技术社区里,经常能看到有人问,改灯 到底该怎么做选型。很多车主在改灯后,出现灯光效果不佳、稳定性差等问题,不…

2026/7/1 15:50:45阅读更多 →
DailyTech-20260630

DailyTech-20260630

每日科技资讯 — 2026年6月30日(周二)聚焦科技圈技术动态。📌 摘要速览 智谱 GLM-5.2 安全基准超越 Claude Opus 4.8——国产模型在网络安全评测上取得进展; 美团一日 9 连发——LongCat 系列全线开源,覆盖音频到定理证…

2026/7/1 15:45:45阅读更多 →
FastMCP 很快,但第一步不是把所有函数都暴露成工具

FastMCP 很快,但第一步不是把所有函数都暴露成工具

FastMCP 很快,但第一步不是把所有函数都暴露成工具 FastMCP 的吸引力很直接:你写一个普通 Python 函数,加上 mcp.tool,它就可以变成 MCP 客户端能发现和调用的工具。对正在给 Claude Code、Codex、Cursor 或 Aider 接工具的人来说…

2026/7/1 15:45:45阅读更多 →
小红书数据采集终极指南:5分钟掌握Python xhs工具完整实战

小红书数据采集终极指南:5分钟掌握Python xhs工具完整实战

小红书数据采集终极指南:5分钟掌握Python xhs工具完整实战 【免费下载链接】xhs 基于小红书 Web 端进行的请求封装。https://reajason.github.io/xhs/ 项目地址: https://gitcode.com/gh_mirrors/xh/xhs 想要获取小红书公开数据却不知从何入手?Py…

2026/7/1 16:41:15阅读更多 →
企业AI培训到底该教工具还是教方法论,这个问题值得想清楚

企业AI培训到底该教工具还是教方法论,这个问题值得想清楚

只教工具,够用但不持久很多企业在启动AI培训时,会不自觉地把重点放在"教会员工使用某些工具"上。这种思路看上去很务实,但实际执行后经常出现一个问题:工具更新了,员工就不会了换了一个场景,之前…

2026/7/1 16:41:15阅读更多 →
AsyncLocal 用法简介

AsyncLocal 用法简介

通过 AsyncLocal 我们可以在一个逻辑上下文中维护一份私有数据,该上下文后续代码中都可以访问和修改这份数据,但另一个无关的上下文是无法访问的。 无论是在新创建的 Task 中还是 await 关键词之后,我们都能够访问前面设置的 AsyncLocal 的数…

2026/7/1 16:41:15阅读更多 →
零代码量化交易软件怎么排:按回测、盯盘和执行边界看

零代码量化交易软件怎么排:按回测、盯盘和执行边界看

零代码量化交易软件的排行不宜按单一名次理解,更适合按能力层级排序:能不能形成规则,能不能回测,能不能盯盘提醒,能不能解释风控,能不能说清执行边界。牛股王股票在普通投资者工具中,可以重点看…

2026/7/1 16:41:15阅读更多 →
会议记录功能单一怎么选?2026年这4个选择标准帮你不踩坑

会议记录功能单一怎么选?2026年这4个选择标准帮你不踩坑

会议记录功能单一怎么选?现在大部分办公软件自带的会议记录,大多只能做到基础语音转文字,既不会提炼重点、拆分待办,也没法把会议、培训内容二次加工用来学习,对需要积累岗位知识的职场新人完全不够用。2026年选工具不…

2026/7/1 16:41:15阅读更多 →
解密万路高并发:基于 Docker 与边缘计算的国标 GB28181/RTSP 视频流统一接入平台架构设计(附源码交付)

解密万路高并发:基于 Docker 与边缘计算的国标 GB28181/RTSP 视频流统一接入平台架构设计(附源码交付)

引言:安防流媒体接入的“诸神黄昏”与集成商痛点 在企业级安防系统和视觉 AI 项目落地中,最让系统架构师和技术决策者头疼的,往往不是算法本身,而是异构视频源的无底洞级适配。 传统现场设备品牌杂乱、新老交替:海康…

2026/7/1 16:36:15阅读更多 →
AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

6个月前的2025年12月,Boris Cherny 公开宣布自己卸载了 IDE。一时间,Vibe Coding 成了全行业最热的话题。6个月后,当我们回过头来拉一份真实账本,发现事情远没有"一句话生成一个App"那么浪漫。本文从产品经理和研发两个…

2026/7/1 4:42:14阅读更多 →
审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

引言:审计结束三个月了,审计员的权限还没关某城商行每年按照监管要求开展至少一次数据安全审计。审计期间,内审部门需要抽样检查各类业务数据——交易流水、客户信息、员工操作日志、权限配置记录。这些数据分布在不同系统中,审计…

2026/7/1 5:19:01阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/1 0:01:44阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/1 0:01:44阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/1 0:01:44阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/1 0:01:44阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/1 0:01:44阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/1 0:01:44阅读更多 →