
前言文件系统是操作系统的核心抽象之一应用的配置缓存、用户数据、离线内容都需要通过文件系统进行持久化存储。HarmonyOS 提供了ohos.file.fs模块封装了完整的 POSIX 文件 I/O 操作——打开、读取、写入、关闭、列出目录、获取文件信息、获取存储空间等核心功能。与 Web 端的 File API 不同HarmonyOS 的文件系统 API 更接近 Unix 系统的open/read/write/close模型。开发者通过文件描述符File descriptor与文件交互获得精细的读写控制。每个 HarmonyOS 应用运行在独立的沙箱文件系统中通过kit.CoreFileKit提供的fileIo命名空间访问。本文通过一个可交互的存储空间管理器Demo深入讲解ohos.file.fs和ohos.file.statvfs的全部核心 API涵盖文件的增删查改和磁盘空间统计。导入与沙箱模型模块导入importfileIofromohos.file.fs;importstatfsfromohos.file.statvfs;两个模块都在kit.CoreFileKit中但分属不同的 API 文件ohos.file.fs— 文件操作open/read/write/close/listFile/stat/unlinkohos.file.statvfs— 文件系统统计getFreeSize/getTotalSize应用沙箱每个 HarmonyOS 应用运行在独立的文件系统沙箱中。通过getContext(this).filesDir获取应用专属的数据目录路径。应用只能读写自己的沙箱目录无法直接访问其他应用的文件或系统目录除非通过特定的 FilePicker API。letcontext:ContextgetContext(this);letappDir:stringcontext.filesDir;// 示例路径: /data/storage/el2/base/haps/entry/files沙箱目录通常在应用卸载时自动清理适合存储用户数据、缓存文件、配置文件等。fileIo.listFile / listFileSync — 目录浏览列出指定目录下的所有文件和子目录名称。同步版本letnames:string[]fileIo.listFileSync(appDir);// 返回: [config.json, cache, test.txt, ...]异步版本Promiseletnames:string[]awaitfileIo.listFile(appDir);过滤选项通过ListFileOptions参数可以按文件名过滤letoptions:fileIo.ListFileOptions{filter:{suffix:[.txt,.json]// 只列出 .txt 和 .json 文件}};letnamesfileIo.listFileSync(appDir,options);同步版本在 UI 线程中执行适合少量文件的目录浏览。对于可能包含大量文件的目录应使用异步 Promise 版本避免阻塞 UI。fileIo.stat / statSync — 文件信息获取文件的元数据包括大小、权限、时间戳、文件类型等。letstatInfo:fileIo.StatfileIo.statSync(/path/to/file.txt);Stat 对象关键属性与方法interfaceStat{readonlyino:bigint;// 文件索引节点号readonlymode:number;// 文件权限位Unix 风格readonlysize:bigint;// 文件大小字节readonlyatimeNs?:bigint;// 最后访问时间纳秒readonlymtimeNs?:bigint;// 最后修改时间纳秒isFile():boolean;// 是否为普通文件isDirectory():boolean;// 是否为目录isBlockDevice():boolean;// 是否为块设备isCharacterDevice():boolean;// 是否为字符设备isFIFO():boolean;// 是否为命名管道isSocket():boolean;// 是否为 socket}实际用法letstatInfofileIo.statSync(filePath);letfileSizeNumber(statInfo.size);// bigint → numberletisDirstatInfo.isDirectory();// 判断类型// 获取修改时间纳秒 → 毫秒 → DateletmtimeMsNumber(statInfo.mtimeNs)/1000000;letmodifiedDatenewDate(mtimeMs);注意size和ino是bigint类型需要Number()转换后才能与其他 number 值进行算术运算。atimeNs和mtimeNs是可选的?因为部分文件系统可能不记录这些时间。fileIo.openSync / open — 打开文件打开或创建文件返回File对象其中包含文件描述符.fd。letfile:fileIo.FilefileIo.openSync(path,mode);OpenMode 常量enumOpenMode{READ_ONLY0o0,// 只读打开WRITE_ONLY0o1,// 只写打开READ_WRITE0o2,// 读写打开CREATE0o100,// 文件不存在时创建TRUNC0o1000,// 打开时截断文件清空APPEND0o2000,// 追加模式NONBLOCK0o4000,// 非阻塞模式SYNC0o4010000// 同步写入}多个模式通过按位或|组合// 创建新文件只写不存在则创建fileIo.openSync(path,fileIo.OpenMode.CREATE|fileIo.OpenMode.WRITE_ONLY);// 只读打开fileIo.openSync(path,fileIo.OpenMode.READ_ONLY);// 追加写入fileIo.openSync(path,fileIo.OpenMode.CREATE|fileIo.OpenMode.WRITE_ONLY|fileIo.OpenMode.APPEND);File 对象interfaceFile{fd:number;// 文件描述符传递给 read/write/closepath:string;// 文件路径}openSync返回的fileIo.File需要通过.fd获取文件描述符再传递给readSync、writeSync和closeSync。fileIo.writeSync / write — 写入文件向打开的文件写入数据。fileIo.writeSync(file.fd,dataString);数据可以是字符串或 ArrayBuffer// 写入字符串fileIo.writeSync(file.fd,Hello HarmonyOS!);// 写入二进制数据letbuffernewArrayBuffer(1024);fileIo.writeSync(file.fd,buffer);完整创建文件示例functioncreateTextFile(path:string,content:string):void{letfilefileIo.openSync(path,fileIo.OpenMode.CREATE|fileIo.OpenMode.WRITE_ONLY);fileIo.writeSync(file.fd,content);fileIo.closeSync(file);}fileIo.readSync / read — 读取文件从打开的文件读取数据到 ArrayBuffer。letbuffernewArrayBuffer(fileSize);fileIo.readSync(file.fd,buffer,{offset:0,length:fileSize});ReadOptionsinterfaceReadOptions{offset?:number;// 缓冲区偏移量length?:number;// 读取长度}ArrayBuffer → 字符串转换读取的原始数据是ArrayBuffer需要手动转换为字符串letuint8Arr:Uint8ArraynewUint8Array(buffer);letresult:string;for(leti0;iuint8Arr.length;i){resultString.fromCharCode(uint8Arr[i]);}这种逐字节转换当文件较大时性能较差。对于大文件100KB建议使用fileIo.createStream()创建流式读写对象或者使用fileIo.read()异步版本分批读取。fileIo.closeSync / close — 关闭文件操作完毕后必须关闭文件释放文件描述符。fileIo.closeSync(file);closeSync接受File对象而不仅仅是文件描述符数字。忘记关闭文件会导致文件描述符泄漏——每个进程的文件描述符数量有限通常 1024 个泄漏过多会导致无法打开新文件。最佳实践使用 try-finally 模式确保关闭letfile:fileIo.File|nullnull;try{filefileIo.openSync(path,fileIo.OpenMode.READ_ONLY);// ... 读取操作 ...}finally{if(file){fileIo.closeSync(file);}}fileIo.unlinkSync / unlink — 删除文件删除指定路径的文件。fileIo.unlinkSync(/path/to/file.txt);最佳实践安全删除删除前检查文件是否存在并确认是文件非目录functionsafeDelete(path:string):boolean{try{if(!fileIo.accessSync(path))returnfalse;letstatInfofileIo.statSync(path);if(!statInfo.isFile())returnfalse;fileIo.unlinkSync(path);returntrue;}catch(e){returnfalse;}}fileIo.accessSync / access — 检查文件检查文件是否存在不打开文件。letexists:booleanfileIo.accessSync(/path/to/file.txt);返回true表示文件存在且可访问但调用可能抛出异常如权限不足等。ohos.file.statvfs —— 存储空间统计ohos.file.statvfs模块提供两个核心函数getTotalSizeSync / getTotalSize获取指定路径所在分区的总容量字节。lettotalBytes:numberstatfs.getTotalSizeSync(context.filesDir);getFreeSizeSync / getFreeSize获取指定路径所在分区的可用空间字节。letfreeBytes:numberstatfs.getFreeSizeSync(context.filesDir);letusedBytes:numbertotalBytes-freeBytes;格式化显示functionformatBytes(bytes:number):string{if(bytes1024)returnbytes B;if(bytes1048576)return(bytes/1024).toFixed(1) KB;if(bytes1073741824)return(bytes/1048576).toFixed(1) MB;return(bytes/1073741824).toFixed(1) GB;}Demo存储空间管理器我们构建了一个完整的文件系统操作 Demo可以在沙箱中创建、查看、删除文件并实时查看存储空间变化。功能模块存储空间卡片— 显示总容量、已使用、可用空间和当前文件数。刷新按钮可实时更新新建文件— 输入文件名和文本内容创建新文件到 sandbox文件列表— 列出应用目录下所有文件和子目录显示文件大小和类型标识查看内容— 点击文件读取并显示其文本内容等宽字体可滚动超过 5000 字节自动截断删除文件— 点击删除按钮移除文件自动刷新列表和空间统计API 速查列表— 8 个核心 API 的名称和说明核心实现目录浏览与文件列表refreshList():void{letnames:string[]fileIo.listFileSync(this.currentPath);letitems:FileItem[][];this.fileCountnames.length;for(leti0;inames.length;i){letfullPaththis.currentPath/names[i];letstatInfo:fileIo.StatfileIo.statSync(fullPath);letisDir:boolean!statInfo.isFile();letsizeStrisDir?[目录]:this.formatBytes(Number(statInfo.size));items.push(newFileItem(names[i],sizeStr,isDir));}this.fileListitems;}核心实现创建文件letfile:fileIo.FilefileIo.openSync(filePath,fileIo.OpenMode.CREATE|fileIo.OpenMode.WRITE_ONLY);fileIo.writeSync(file.fd,this.newFileContent);fileIo.closeSync(file);核心实现读取文件letstatInfofileIo.statSync(filePath);letfileSizeNumber(statInfo.size);letfilefileIo.openSync(filePath,fileIo.OpenMode.READ_ONLY);letbuffernewArrayBuffer(fileSize);fileIo.readSync(file.fd,buffer,{offset:0,length:fileSize});// ArrayBuffer → string conversionletuint8ArrnewUint8Array(buffer);letresult;for(leti0;iuint8Arr.length;i){resultString.fromCharCode(uint8Arr[i]);}fileIo.closeSync(file);核心实现存储空间统计lettotalBytesstatfs.getTotalSizeSync(this.currentPath);letfreeBytesstatfs.getFreeSizeSync(this.currentPath);letusedBytestotalBytes-freeBytes;性能与最佳实践1. 同步 vs 异步同步 API*Sync在 UI 线程执行适合小文件10KB和少量文件操作。对于大文件读写或大量文件操作应使用异步 Promise 版本避免阻塞 UI。// 适合同步小文件读取letstatInfofileIo.statSync(path);// 应该异步大文件拷贝awaitfileIo.copyFile(src,dest);2. 文件描述符管理每个打开的文件必须被关闭。即使发生异常也要关闭——closeSync同时接受number和File类型letfile:fileIo.FilefileIo.openSync(path,fileIo.OpenMode.READ_ONLY);try{// 操作...}finally{fileIo.closeSync(file);}3. 大文件读取对于超过数 MB 的文件不要一次性读入内存。使用fileIo.createStream()创建流式读写对象分批读取letstreamfileIo.createStreamSync(path,r);letbuffernewArrayBuffer(4096);// 4KB 块letbytesRead:number;while((bytesReadstream.readSync(buffer))0){// 处理 buffer 中的 bytesRead 字节}stream.closeSync();4. 存储空间检查在写大文件前先检查可用空间letfreeBytesstatfs.getFreeSizeSync(dirPath);if(freeBytesestimatedSize){// 空间不足提示用户}5. 路径拼接避免手动拼接路径字符串可能导致双斜杠或反斜杠问题。使用路径常量// 推荐letfullPaththis.currentPath/fileName;// 对于复杂路径操作考虑 fileUri 模块与 Preferences 的对比特性ohos.file.fsohos.data.preferences用途通用文件存储键值对配置数据类型任意文本/二进制基本类型string/number/boolean文件位置任意沙箱路径固定配置目录并发安全需自行处理框架保证适合场景文档、缓存、日志用户设置、配置项对于配置文件开关、选项、用户偏好使用Preferences更方便。对于用户数据文本文档、JSON 缓存、日志文件使用ohos.file.fs更灵活。总结本文详细讲解了 HarmonyOS 文件系统操作的核心 APIlistFile/listFileSync— 目录浏览获取文件和子目录名列表stat/statSync— 获取文件元数据大小、类型、权限、时间戳open/openSync— 打开/创建文件返回 File 对象write/writeSync— 写入字符串或 ArrayBuffer 数据read/readSync— 读取数据到 ArrayBufferclose/closeSync— 关闭文件释放文件描述符unlink/unlinkSync— 删除文件access/accessSync— 检查文件是否存在statfs.getTotalSizeSync/getFreeSizeSync— 分区容量和可用空间HarmonyOS 的文件 I/O 模型直接继承自 Unix 的open-read-write-close范式提供了精细的控制能力。结合应用沙箱机制既保证了数据安全性又提供了灵活的文件操作接口。存储空间管理器 Demo 是一个实用的开发工具展示了文件 CRUD 操作的完整流程可直接在真机或模拟器上运行体验。