鸿蒙 6.1 API 23 开发坑系列篇 8:@ohos.file.fs 文件管理坑——writeSync/readSync 是 namespace 顶层函数不是 File 实例方法 + 第一参传 file.fd 文件描述符根因

本文是「鸿蒙 6.1 API 23 开发坑系列」第 8 篇(非 UI 系第 2 篇)。本篇讲 @ohos.file.fs namespace(API 6+,鸿蒙 6.1 API 23 基座)——文件读写 writeSync/readSync/openSync/closeSync/statSync 顶层函数 + File 对象 + OpenMode/ReadOptions/WriteOptions 类型。鸿蒙坑根因:① writeSync/readSync 是 namespace 顶层函数不是 File 实例方法(file.writeSync() 编译错 Property does not exist);② 第一参传 file.fd 文件描述符(number)不是 file 对象也不是 path 字符串;③ ReadOptions 不带 encoding(只有 offset/length,读出来是 ArrayBuffer 裸字节自己解码);④ WriteOptionsencoding(写字符串时指定编码,写 ArrayBuffer 不用);⑤ fs.closeSync(file) 关闭传 File 对象不是 fd(跟 writeSync 第一参 fd 不同);⑥ OpenMode enum 常量 READ_WRITE/CREATE/TRUNC 不是 flags 数字。

一、开篇:鸿蒙 fs 不是 Node fs,是「namespace 顶层函数 + file.fd 文件描述符 + ArrayBuffer 裸字节」

你写 Node 时,文件读写用 fs 模块(fs.writeFileSync/fs.readFileSync 顶层函数,传 path 字符串,读出来是 Buffer/字符串):

// Node fs:fs.writeFileSync 顶层函数传 path,读出来是 Buffer/字符串
import fs from 'fs'  // ✅ Node fs 模块

fs.writeFileSync('/tmp/test.txt', 'hello node fs')  // ✅ 传 path 字符串,不是 fd
const content: string = fs.readFileSync('/tmp/test.txt', 'utf-8')  // ✅ 传 path,第二参 encoding 自动解码
// Node fs.writeFileSync/readFileSync 是顶层函数,传 path 字符串,读出来自动解码到 string

你写鸿蒙 ArkTS 时,文件读写用 fs.writeSync(fd, content) namespace 顶层函数(第一参传 file.fd 文件描述符不是 path,ReadOptions 无 encoding 读出来是 ArrayBuffer 裸字节):

// ArkTS fs.writeSync:namespace 顶层函数第一参传 file.fd,读出来 ArrayBuffer 裸字节自己解码
import fs, { ReadOptions, WriteOptions } from '@ohos.file.fs'  // ✅ default import + 类型 named import
import { common } from '@kit.AbilityKit'
import { buffer } from '@kit.ArkTS'

const context = getContext(this) as common.UIAbilityContext
const filePath = context.filesDir + '/test.txt'
// ✅ fs.openSync(path, OpenMode) 造 File 对象(file.fd 是文件描述符 number)
const file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)

// ✅ fs.writeSync 是 namespace 顶层函数,第一参传 file.fd 文件描述符(不是 path 字符串)
fs.writeSync(file.fd, 'hello harmony fs')  // ✅ 第一参 file.fd 不是 path

// ✅ fs.readSync 读出来是 ArrayBuffer 裸字节(ReadOptions 无 encoding 不自动解码)
const buf = new ArrayBuffer(1024)
const readLen = fs.readSync(file.fd, buf, { offset: 0, length: buf.byteLength } as ReadOptions)  // ✅ 无 encoding
const content: string = buffer.from(buf, 0, readLen).toString()  // ✅ 自己解码 ArrayBuffer 到 string
// 鸿蒙坑根因:writeSync namespace 顶层函数第一参 file.fd,ReadOptions 无 encoding 读 ArrayBuffer 裸字节

Node fs vs 鸿蒙 fs 的区别:Node 把文件读写当模块顶层函数(fs.writeFileSync(path, content) 传 path 字符串,fs.readFileSync(path, 'utf-8') 传 encoding 自动解码到 string),ArkTS 把文件读写当 namespace 顶层函数(fs.writeSync(file.fd, content) 第一参传 file.fd 文件描述符不是 path,fs.readSync(file.fd, buf, options) 读出来是 ArrayBuffer 裸字节无 encoding 不自动解码)。根因不是模块函数是 namespace 顶层函数——鸿蒙 writeSync/readSync 第一参传 file.fd 文件描述符(先 openSyncFile 对象拿 fd),ReadOptionsencoding 读出来是 ArrayBuffer 裸字节自己用 buffer.from().toString() 解码。

二、根因:鸿蒙 @ohos.file.fs 的六个绑定机制

鸿蒙 @ohos.file.fs namespace(API 6+)核心导出 fs.openSync/fs.writeSync/fs.readSync/fs.closeSync/fs.statSync 顶层函数 + File interface + OpenMode/ReadOptions/WriteOptions/Stat 类型。绑定机制来自六重根因。

机制 1:writeSync/readSync 是 namespace 顶层函数不是 File 实例方法

鸿蒙坑根因:writeSync/readSyncfs namespace 顶层函数,不是 File 实例方法:

// ❌ 鸿蒙坑:writeSync/readSync 是 namespace 顶层函数不是 File 实例方法
import fs from '@ohos.file.fs'

const file = fs.openSync('/tmp/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)

// ❌ File 实例方法不存在(编译错 Property does not exist)
file.writeSync('content')  // ❌ File interface 没有 writeSync 实例方法
file.readSync(buffer)      // ❌ File interface 没有 readSync 实例方法

// ✅ 正确用法:fs.writeSync/fs.readSync namespace 顶层函数,第一参传 file.fd
fs.writeSync(file.fd, 'content')  // ✅ namespace 顶层函数 + file.fd
fs.readSync(file.fd, buffer, options)  // ✅ namespace 顶层函数 + file.fd
// 鸿蒙坑根因:writeSync/readSync 是 namespace 顶层函数不是 File 实例方法,第一参传 file.fd

namespace 顶层函数坑根因:鸿蒙 @ohos.file.fs.d.tswriteSync/readSync 声明是 export function writeSync(fd: number, ...)export function readSync(fd: number, ...)(namespace 顶层函数,不是 File interface 的方法)。File interface 只有 fd/name/path 属性没有读写方法。鸿蒙坑file.writeSync() 触发 Property 'writeSync' does not exist on type 'File' 编译错——File 是数据对象(持 fd/name/path)不是读写对象,读写必须走 fs.writeSync(file.fd, ...) namespace 顶层函数。Node fs.writeFileSync 也是模块顶层函数但传 path 字符串,鸿蒙 fs.writeSyncfile.fd 文件描述符(先 openSync 拿 fd)。

机制 2:第一参传 file.fd 文件描述符不是 file 对象也不是 path 字符串

鸿蒙坑根因:writeSync/readSync 第一参传 file.fd 文件描述符(number),不是 file 对象也不是 path 字符串:

// ❌ 鸿蒙坑:第一参传 file.fd 文件描述符不是 file 对象也不是 path 字符串
import fs from '@ohos.file.fs'

const file = fs.openSync('/tmp/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)

// ❌ 传 file 对象编译错(writeSync 第一参类型是 number 不是 File)
fs.writeSync(file, 'content')  // ❌ 第一参类型 number 不是 File 对象
// ❌ 传 path 字符串编译错(writeSync 第一参不是 path)
fs.writeSync('/tmp/test.txt', 'content')  // ❌ 第一参不是 path 字符串是 fd

// ✅ 正确用法:第一参传 file.fd 文件描述符(number 类型)
fs.writeSync(file.fd, 'content')  // ✅ file.fd 是 number 文件描述符
// 鸿蒙坑根因:第一参传 file.fd 文件描述符(number),不是 file 对象也不是 path 字符串

file.fd 文件描述符坑根因:鸿蒙 fs.writeSync(fd: number, buffer: ArrayBuffer | string, options?: WriteOptions) 的第一参类型是 number(文件描述符 fd),不是 File 对象也不是 path 字符串。fs.openSync(path, OpenMode) 返回 File 对象,file.fdnumber 类型的文件描述符。鸿蒙坑:传 file 对象触发 Type 'File' is not assignable to type 'number' 编译错,传 path 字符串触发 Type 'string' is not assignable to type 'number' 编译错——必须传 file.fd(先 openSync 拿 fd 再传给 writeSync/readSync)。Node fs.writeFileSync(path, content) 传 path 字符串不需要先 open,鸿蒙 fs.writeSync(file.fd, content) 必须先 openSync 拿 fd。

机制 3:ReadOptions 不带 encoding——读出来是 ArrayBuffer 裸字节自己解码

鸿蒙坑根因:ReadOptions 不带 encoding(只有 offset/length),读出来是 ArrayBuffer �裸字节自己解码:

// ❌ 鸿蒙坑:ReadOptions 不带 encoding(读出来是 ArrayBuffer 裸字节)
import fs, { ReadOptions } from '@ohos.file.fs'
import { buffer } from '@kit.ArkTS'

const file = fs.openSync('/tmp/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
fs.writeSync(file.fd, 'hello h8 fs')

// ❌ ReadOptions 带 encoding 编译错(encoding 不在 ReadOptions 类型里)
const badReadOptions: ReadOptions = { offset: 0, length: 20, encoding: 'utf-8' }  // ❌ encoding 不存在

// ✅ 正确用法:ReadOptions 只有 offset/length,读出来是 ArrayBuffer 裸字节
const arrayBuffer = new ArrayBuffer(1024)
const readOptions: ReadOptions = { offset: 0, length: arrayBuffer.byteLength }  // ✅ 无 encoding
const readLen = fs.readSync(file.fd, arrayBuffer, readOptions)  // ✅ 读出来是 ArrayBuffer 裸字节

// ✅ 用 @kit.ArkTS buffer 自己解码 ArrayBuffer 到 string(鸿蒙不自动解码)
const content: string = buffer.from(arrayBuffer, 0, readLen).toString()  // ✅ buffer.toString() 解码
// 鸿蒙坑根因:ReadOptions 无 encoding 读出来 ArrayBuffer 裸字节,用 buffer.from().toString() 自己解码

ReadOptions 无 encoding 坑根因:鸿蒙 ReadOptions 的属性只有 offset?: number(读取偏移)和 length?: number(读取长度),没有 encoding 字段。fs.readSync 读出来是 ArrayBuffer 裸字节(二进制),不自动解码到 string。鸿蒙坑ReadOptionsencoding 触发 Object literal may only specify known properties, and 'encoding' does not exist in type 'ReadOptions' 编译错——读出来的 ArrayBuffer 必须用 @kit.ArkTSbuffer.from(arrayBuffer, 0, readLen).toString() 自己解码到 string。Node fs.readFileSync(path, 'utf-8') 第二参传 encoding 自动解码到 string,鸿蒙 fs.readSync(fd, buf, options)ReadOptions 无 encoding 不自动解码——读 ArrayBuffer �裸字节自己解码。

机制 4:WriteOptions 带 encoding——写字符串时指定编码

鸿蒙坑根因:WriteOptionsencoding(写字符串时指定编码,写 ArrayBuffer 不用):

// ✅ WriteOptions 带 encoding(写字符串时指定编码,写 ArrayBuffer 不用)
import fs, { WriteOptions } from '@ohos.file.fs'

const file = fs.openSync('/tmp/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)

// ✅ WriteOptions 带 encoding(写字符串时指定 utf-8 编码)
const writeOptions: WriteOptions = { offset: 0, length: 11, encoding: 'utf-8' }  // ✅ 带 encoding
fs.writeSync(file.fd, 'hello h8 enc', writeOptions)  // ✅ 写字符串带 encoding

// ✅ 写 ArrayBuffer 不用 encoding(二进制直接写)
const buf = new ArrayBuffer(10)
const writeOptions2: WriteOptions = { offset: 0, length: 10 }  // ✅ 写 ArrayBuffer 不用 encoding
fs.writeSync(file.fd, buf, writeOptions2)
// 鸿蒙坑根因:WriteOptions 带 encoding(写字符串时指定编码),ReadOptions 不带 encoding

WriteOptions 带 encoding 坑根因:鸿蒙 WriteOptions 的属性是 offset?: number/length?: number/encoding?: string(带 encoding),跟 ReadOptions(无 encoding)不同。鸿蒙坑WriteOptionsencoding 指定写字符串时的编码('utf-8'/'utf-16' 等),写 ArrayBuffer 二进制不用 encoding(直接写裸字节);ReadOptions 无 encoding 读出来是 ArrayBuffer 裸字节。Node fs.writeFileSync(path, content, { encoding: 'utf-8' }) 的 encoding 是可选的(写字符串默认 utf-8),鸿蒙 WriteOptions.encoding 也是可选的但写字符串时显式指定更安全。鸿蒙坑核心ReadOptions 无 encoding 读 ArrayBuffer 裸字节自己解码,WriteOptions 带 encoding 写字符串时指定编码——读写 encoding 不对称。

机制 5:closeSync(file) 关闭传 File 对象不是 fd——跟 writeSync 第一参 fd 不同

鸿蒙坑根因:fs.closeSync(file) 关闭传 File 对象不是 fd(跟 writeSync 第一参 fd 不同):

// ❌ 鸿蒙坑:closeSync(file) 关闭传 File 对象不是 fd(跟 writeSync 第一参 fd 不同)
import fs from '@ohos.file.fs'

const file = fs.openSync('/tmp/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
fs.writeSync(file.fd, 'content')

// ❌ closeSync 传 fd 编译错(closeSync 第一参类型是 File 不是 number)
fs.closeSync(file.fd)  // ❌ 第一参类型 File 不是 number(file.fd 是 number)

// ✅ 正确用法:closeSync(file) 传 File 对象(不是 file.fd 文件描述符)
fs.closeSync(file)  // ✅ 传 File 对象不是 fd
// 鸿蒙坑根因:closeSync(file) 传 File 对象,writeSync(file.fd, ...) 传 fd——两个第一参类型不同

closeSync vs writeSync 第一参坑根因:鸿蒙 fs.closeSync(file: File): void 的第一参类型是 File 对象,跟 fs.writeSync(fd: number, ...) 的第一参类型 number(fd)不同。鸿蒙坑fs.closeSync(file.fd) 触发 Type 'number' is not assignable to type 'File' 编译错——closeSyncFile 对象(file),writeSync/readSyncfdfile.fd),两个第一参类型不同。Node fs.closeSync(fd) 传 fd 数字(跟 fs.openSync 返回的 fd 一致),鸿蒙 fs.closeSync(file) 传 File 对象——鸿蒙的 closeSyncwriteSync/readSync 第一参类型不一致是坑。

机制 6:OpenMode enum 常量 READ_WRITE/CREATE/TRUNC 不是 flags 数字

鸿蒙坑根因:OpenMode enum 常量 READ_ONLY/WRITE_ONLY/READ_WRITE/CREATE/TRUNC/APPEND,不是 flags 数字:

// ❌ 鸿蒙坑:OpenMode enum 常量不是 flags 数字(fs.openSync 第二参用 OpenMode 不用数字)
import fs from '@ohos.file.fs'

// ❌ 传 flags 数字编译错(openSync 第二参类型是 OpenMode enum 不是 number)
const badFile = fs.openSync('/tmp/test.txt', 0o666)  // ❌ 第二参类型 OpenMode 不是 number
// ❌ 传字符串 flags 编译错(不是 'r'/'w'/'r+' 字符串)
const badFile2 = fs.openSync('/tmp/test.txt', 'r+')  // ❌ 不是字符串 flags 是 OpenMode enum

// ✅ 正确用法:OpenMode enum 常量 | 位运算组合(READ_WRITE | CREATE | TRUNC)
const file = fs.openSync('/tmp/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE | fs.OpenMode.TRUNC)  // ✅ OpenMode enum
// ✅ OpenMode enum 常量:READ_ONLY=0o0 / WRITE_ONLY=0o1 / READ_WRITE=0o2 / CREATE=0o100 / TRUNC=0o1000 / APPEND=0o2000
// 鸿蒙坑根因:OpenMode enum 常量 | 位运算组合,不是 flags 数字也不是 'r'/'w' 字符串

OpenMode enum 坑根因:鸿蒙 fs.openSync(path: string, mode: OpenMode): File 的第二参类型是 OpenMode enum(位标志 enum),常量 READ_ONLY=0o0/WRITE_ONLY=0o1/READ_WRITE=0o2/CREATE=0o100/TRUNC=0o1000/APPEND=0o2000,用 | 位运算组合。鸿蒙坑:传 flags 数字触发 Type 'number' is not assignable to type 'OpenMode' 编译错,传字符串 'r+'/'w' 触发 Type 'string' is not assignable to type 'OpenMode' 编译错——必须用 fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE enum 常量位运算。Node fs.openSync(path, 'r+') 传字符串 flags,鸿蒙 fs.openSync(path, OpenMode.READ_WRITE) 传 enum 常量;Node fs.openSync(path, 0o666) 传数字 mode,鸿蒙传 OpenMode enum 不是数字。

三、真机配图:鸿蒙 @ohos.file.fs 文件管理坑——namespace 顶层函数 + file.fd + ReadOptions 无 encoding

在这里插入图片描述
在这里插入图片描述

真机配图展示鸿蒙 @ohos.file.fs 文件管理坑:

  • 初始态:鸿蒙 6.1 @ohos.file.fs 文件管理坑标题,4 个验证按钮(① writeSync namespace 顶层函数 / ② ReadOptions 无 encoding / ③ WriteOptions 带 encoding / ④ openSync+closeSync+statSync 生命周期),文件状态(writeStatus 未写 + readStatus 未读 + fdValue 未开 + writeLen/readLen/readContent),要点说明 7 条
  • writeSync namespace 顶层函数态:点击「① 验证 writeSync namespace 顶层函数」按钮,显示「✅ fs.writeSync namespace 顶层函数验证:不是 File 实例方法,第一参传 file.fd」+ file.fd 值 + writeLen——writeSync namespace 顶层函数 + file.fd 验证
  • ReadOptions 无 encoding 态:点击「② 验证 ReadOptions 无 encoding」按钮,显示「✅ ReadOptions 无 encoding 验证:读出来是 ArrayBuffer,用 buffer.toString() 自己解码」+ readLen + readContent——ReadOptions 无 encoding 读 ArrayBuffer 裸字节验证
  • WriteOptions 带 encoding 态:点击「③ 验证 WriteOptions 带 encoding」按钮,显示「✅ WriteOptions 带 encoding 验证:写字符串时指定 utf-8 编码」+ writeLen——WriteOptions 带 encoding 写字符串指定编码验证
  • openSync+closeSync+statSync 生命周期态:点击「④ 验证 openSync+closeSync+statSync 生命周期」按钮,显示「✅ 文件生命周期验证:openSync + writeSync + statSync + closeSync」+ file.fd + stat.size 值——完整文件生命周期验证

四、真解法:鸿蒙 @ohos.file.fs 的四个场景

场景 1:openSync 造 File + writeSync(file.fd) 写文件 + closeSync(file) 关闭——90% 场景首选

基础文件写入用 fs.openSyncFile + fs.writeSync(file.fd, content) 写 + fs.closeSync(file) 关闭:

// ✅ 场景 1:openSync 造 File + writeSync(file.fd) 写文件 + closeSync(file) 关闭(API 6,90% 场景首选)
import fs, { WriteOptions } from '@ohos.file.fs'  // ✅ default import + 类型 named import
import { common } from '@kit.AbilityKit'

@Entry
@Component
struct Index {
  @State writeStatus: string = '(未写)'
  private file: fs.File | null = null  // ✅ 持引用避免析构

  writeToFile() {
    // ✅ 获取应用沙箱目录路径(getContext(this) deprecated 但能跑,新版用 this.getUIContext.getHostContext)
    const context = getContext(this) as common.UIAbilityContext
    const filePath = context.filesDir + '/h8_demo.txt'
    // ✅ fs.openSync(path, OpenMode) 造 File 对象(OpenMode enum 常量 | 位运算组合)
    this.file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE | fs.OpenMode.TRUNC)
    // ✅ fs.writeSync(file.fd, content) namespace 顶层函数——第一参 file.fd 不是 path
    const writeOptions: WriteOptions = { encoding: 'utf-8' }  // ✅ WriteOptions 带 encoding
    const writeLen = fs.writeSync(this.file.fd, 'hello h8 fs writeSync', writeOptions)
    this.writeStatus = `✅ writeSync 写入 ${writeLen} 字节到 file.fd=${this.file.fd}`
    // ✅ fs.closeSync(file) 关闭传 File 对象不是 fd(跟 writeSync 第一参 fd 不同)
    fs.closeSync(this.file)  // ✅ 传 File 对象不是 file.fd
    this.file = null
  }

  build() { Column({ space: 8 }) { Text(this.writeStatus).fontSize(12) } }
}
// openSync + writeSync(file.fd) + closeSync(file):90% 场景首选,namespace 顶层函数 + file.fd

鸿蒙 @ohos.file.fs API 真名坑import fs, { ReadOptions, WriteOptions } from '@ohos.file.fs'(default import + 类型 named import,ReadOptions/WriteOptions 是 named export 不是嵌套在 namespace 里);fs.openSync(path: string, mode: OpenMode): File(造 File 对象,OpenMode enum 常量不是 flags 数字);fs.writeSync(fd: number, buffer: ArrayBuffer | string, options?: WriteOptions): number(namespace 顶层函数,第一参 fd 文件描述符不是 path);fs.readSync(fd: number, buffer: ArrayBuffer, options?: ReadOptions): number(读出来是 ArrayBuffer 裸字节);fs.closeSync(file: File): void(关闭传 File 对象不是 fd);fs.statSync(file: string | number | File): Stat(获取文件信息,Stat.size 是文件大小);SysCap SystemCapability.FileManagement.File.FileIO权限 无需特殊权限(应用沙箱目录内读写)。

场景 2:readSync 读 ArrayBuffer 裸字节 + buffer.from().toString() 自己解码

读文件用 fs.readSync(file.fd, buf, ReadOptions) 读 ArrayBuffer 裸字节 + buffer.from().toString() 解码:

// ✅ 场景 2:readSync 读 ArrayBuffer 裸字节 + buffer.from().toString() 自己解码(API 6)
import fs, { ReadOptions } from '@ohos.file.fs'
import { common } from '@kit.AbilityKit'
import { buffer } from '@kit.ArkTS'  // ✅ @kit.ArkTS buffer 解码 ArrayBuffer

const context = getContext(this) as common.UIAbilityContext
const filePath = context.filesDir + '/h8_demo.txt'
const file = fs.openSync(filePath, fs.OpenMode.READ_ONLY)  // ✅ 只读模式打开

// ✅ ReadOptions 无 encoding(只有 offset/length),读出来是 ArrayBuffer 裸字节
const arrayBuffer = new ArrayBuffer(1024)
const readOptions: ReadOptions = { offset: 0, length: arrayBuffer.byteLength }  // ✅ 无 encoding
const readLen = fs.readSync(file.fd, arrayBuffer, readOptions)  // ✅ 读 ArrayBuffer 裸字节

// ✅ buffer.from(arrayBuffer, 0, readLen).toString() 解码 ArrayBuffer 到 string
const content: string = buffer.from(arrayBuffer, 0, readLen).toString()  // ✅ 自己解码
console.info('文件内容: ' + content)  // ✅ content 是解码后的 string
fs.closeSync(file)
// readSync ArrayBuffer 裸字节 + buffer.toString() 解码:ReadOptions 无 encoding 自己解码

鸿蒙 readSync + buffer 解码 API 真名坑fs.readSync(fd: number, buffer: ArrayBuffer, options?: ReadOptions): number(返回读取字节数,读出来是 ArrayBuffer 裸字节不是 string);ReadOptions 只有 offset?: number/length?: number 无 encoding;@kit.ArkTSbuffer.from(arrayBuffer, byteOffset, length).toString() 解码 ArrayBuffer 到 string;鸿蒙坑:Node fs.readFileSync(path, 'utf-8') 第二参传 encoding 自动解码到 string,鸿蒙 fs.readSync(fd, buf, options)ReadOptions 无 encoding 读出来 ArrayBuffer 裸字节——必须用 buffer.from().toString() 自己解码(@kit.ArkTS 的 buffer 不是 Node 的 Buffer)。

场景 3:WriteOptions 带 encoding 写字符串 + 不带 encoding 写 ArrayBuffer

写字符串用 WriteOptions.encoding 指定编码,写 ArrayBuffer 不用 encoding:

// ✅ 场景 3:WriteOptions 带 encoding 写字符串 + 不带 encoding 写 ArrayBuffer(API 6)
import fs, { WriteOptions } from '@ohos.file.fs'

const file = fs.openSync('/tmp/h8_enc.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE | fs.OpenMode.TRUNC)

// ✅ 写字符串带 encoding(指定 utf-8 编码)
const strOptions: WriteOptions = { offset: 0, length: 11, encoding: 'utf-8' }  // ✅ 带 encoding
fs.writeSync(file.fd, 'hello h8 enc', strOptions)  // ✅ 写字符串带 encoding

// ✅ 写 ArrayBuffer 不用 encoding(二进制直接写裸字节)
const buf = new ArrayBuffer(10)
const binOptions: WriteOptions = { offset: 0, length: 10 }  // ✅ 写 ArrayBuffer 不用 encoding
fs.writeSync(file.fd, buf, binOptions)  // ✅ 写 ArrayBuffer 不用 encoding
fs.closeSync(file)
// WriteOptions 带 encoding 写字符串 + 不带 encoding 写 ArrayBuffer:读写 encoding 不对称

鸿蒙 WriteOptions encoding API 真名坑WriteOptions 属性 offset?: number/length?: number/encoding?: string(带 encoding);写字符串时 encoding 指定编码('utf-8'/'utf-16'),写 ArrayBuffer 二进制不用 encoding;鸿蒙坑ReadOptions 无 encoding 读 ArrayBuffer 裸字节自己解码,WriteOptions 带 encoding 写字符串时指定编码——读写 encoding 不对称是鸿蒙坑核心。Node fs.writeFileSync(path, string, { encoding: 'utf-8' })fs.readFileSync(path, 'utf-8') 读写都带 encoding,鸿蒙只有 WriteOptions 带 encoding,ReadOptions 无 encoding。

场景 4:statSync 获取文件信息 + listFileSync 列目录 + unlinkSync 删除

文件信息用 fs.statSync,列目录用 fs.listFileSync,删除用 fs.unlinkSync

// ✅ 场景 4:statSync 获取文件信息 + listFileSync 列目录 + unlinkSync 删除(API 6)
import fs from '@ohos.file.fs'

const file = fs.openSync('/tmp/h8_stat.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
fs.writeSync(file.fd, 'stat demo')

// ✅ fs.statSync(file) 获取文件信息(file 可以是 path 或 fd 或 File)
const stat = fs.statSync(file.fd)  // ✅ 传 fd(也可以传 path 或 File 对象)
console.info('文件大小: ' + stat.size)  // ✅ Stat.size 是文件字节数
console.info('修改时间: ' + stat.modifiedTime)  // ✅ Stat.modifiedTime 是修改时间

fs.closeSync(file)

// ✅ fs.listFileSync(path) 列目录文件(返回 string[] 文件名数组)
const files: string[] = fs.listFileSync('/tmp')  // ✅ 返回目录下文件名数组
console.info('目录文件数: ' + files.length)

// ✅ fs.unlinkSync(path) 删除文件(传 path 字符串不是 fd)
fs.unlinkSync('/tmp/h8_stat.txt')  // ✅ 传 path 字符串删除文件
// statSync + listFileSync + unlinkSync:statSync 传 fd/path/File,unlinkSync 传 path

鸿蒙 statSync + listFileSync + unlinkSync API 真名坑fs.statSync(file: string | number | File): Stat(获取文件信息,第一参可以是 path 字符串/fd 数字/File 对象三选一,跟 writeSync 只传 fd 不同);fs.listFileSync(path: string): string[](列目录文件名数组);fs.unlinkSync(path: string): void(删除文件,传 path 字符串不是 fd);Stat 属性 size: number/modifiedTime: number/hasNoAccess: boolean鸿蒙坑statSync 第一参可以是 path/fd/File 三种类型(比 writeSync 只传 fd 姬活),unlinkSync 传 path 字符串不是 fd(跟 closeSync 传 File 又不同)——鸿蒙 fs 各函数第一参类型不统一是坑(writeSync/readSync 传 fd,closeSync 传 File,unlinkSync 传 path,statSync 传 path/fd/File)。

五、一句话哲学

写鸿蒙 ArkTS 记住:fs 不是 Node fs 是「namespace 顶层函数 + file.fd 文件描述符 + ArrayBuffer 裸字节」——鸿蒙 6.1 API 23 @ohos.file.fs namespace(API 6+,鸿蒙 6.1 API 23 基座,fs.openSync/writeSync/readSync/closeSync/statSync/listFileSync/unlinkSync 顶层函数 + File interface + OpenMode/ReadOptions/WriteOptions/Stat 类型,SysCap SystemCapability.FileManagement.File.FileIO,无需特殊权限应用沙箱内读写)。根因不是模块函数是 namespace 顶层函数——writeSync/readSync 是 namespace 顶层函数不是 File 实例方法(✅ fs.writeSync(file.fd, content) namespace 顶层函数,❌ file.writeSync() 编译错 Property 'writeSync' does not exist on type 'File'File interface 只有 fd/name/path 属性无读写方法),第一参传 file.fd 文件描述符(number)不是 file 对象也不是 path 字符串(✅ fs.writeSync(file.fd, ...) 第一参 number,❌ fs.writeSync(file, ...) 触发 Type 'File' is not assignable to type 'number',❌ fs.writeSync('/path', ...) 触发 Type 'string' is not assignable to type 'number',先 openSync 拿 fd 再传给 writeSync/readSync),ReadOptions 不带 encoding(只有 offset/length,读出来是 ArrayBuffer 裸字节,用 @kit.ArkTS buffer.from(buf, 0, readLen).toString() 自己解码,❌ ReadOptionsencoding 触发 Object literal may only specify known properties, and 'encoding' does not exist 编译错),WriteOptionsencoding(写字符串时指定 'utf-8' 编码,写 ArrayBuffer 不用),读写 encoding 不对称是鸿蒙坑核心(WriteOptions 带 encoding,ReadOptions 无 encoding),fs.closeSync(file) 关闭传 File 对象不是 fd(跟 writeSync 第一参 fd 类型不同,❌ closeSync(file.fd) 触发 Type 'number' is not assignable to type 'File'),OpenMode enum 常量 READ_ONLY/WRITE_ONLY/READ_WRITE/CREATE/TRUNC/APPEND 位运算组合不是 flags 数字也不是 'r'/'w' 字符串,各函数第一参类型不统一(writeSync/readSync 传 fd,closeSync 传 File,unlinkSync 传 path,statSync 传 path/fd/File 三选一)。namespace 顶层函数 + file.fd + ReadOptions 无 encoding + WriteOptions 带 encoding + closeSync File + OpenMode enum 是鸿蒙 6.1 @ohos.file.fs 文件管理坑核心!

能力系列回链

  • 鸿蒙 7.0 新特性篇 1~17(沉浸式毛玻璃/Component3D/智能体框架/方舟引擎/星盾安全/星河互联/空间音频/可变字体/游戏快启/分布式数据盾/LTPO 可变帧率/AI 文档识别/多形态服务窗口/AI 反诈/机密计算/空间计算/小艺全面进化)
  • 鸿蒙 6.1 API 23 开发坑系列篇 1「ArkUI.modifier 装饰器坑」——attributeModifier + AttributeModifier 状态化节点修改器
  • 鸿蒙 6.1 API 23 开发坑系列篇 2「arkui.componentSnapshot 组件截图坑」——get/getSync/createFromBuilder 返回 image.PixelMap 像素图
  • 鸿蒙 6.1 API 23 开发坑系列篇 3「arkui.node 节点坑」——NodeController abstract class makeNode override + BuilderNode WrappedBuilder
  • 鸿蒙 6.1 API 23 开发坑系列篇 4「arkui.UIContext UI 上下文坑」——runScopedTask 不是 runScopedOnUiThread + 11 个子管理器
  • 鸿蒙 6.1 API 23 开发坑系列篇 5「arkui.observer UI 观察器坑」——uiObserver namespace 真名不是 observer + on type string literal
  • 鸿蒙 6.1 API 23 开发坑系列篇 6「@ohos.animator 动画器坑」——import @kit.ArkUI 不是 @ohos.animator + onFrame 驼峰不是废弃 onframe + getUIContext().createAnimator 不是废弃 animator.create + 持引用 + aboutToDisappear cancel
  • 鸿蒙 6.1 API 23 开发坑系列篇 7「@ohos.net.http HTTP 请求坑」——HttpDataType 常量是 STRING 不是 STRING_TYPE + HttpRequest 是 interface 不能 new + http.createHttp() 工厂造实例 + on/off 监听不是 addEventListener + header Record 不是 Headers + RequestMethod enum 不是字符串
  • 鸿蒙 6.1 API 23 开发坑系列篇 8「@ohos.file.fs 文件管理坑」——writeSync/readSync 是 namespace 顶层函数不是 File 实例方法 + 第一参传 file.fd 文件描述符 + ReadOptions 无 encoding 读 ArrayBuffer 裸字节 + WriteOptions 带 encoding 写字符串指定编码 + closeSync(file) 传 File 不是 fd + OpenMode enum 不是 flags 数字(本文)
Logo

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

更多推荐