Node 20/21中fs.writeFileSync写入TMPDIR触发EACCES权限错误
Node.js 20/21中
fs.readFileSync使用a+标志创建文件导致权限错误的问题 问题概述
一段读取并修改JSON文件的代码在Node.js 18中可正常运行,但在Node.js 20/21中执行时触发EACCES权限错误——目标文件被创建后权限为0000,完全没有读写权限,导致后续写入操作失败。
错误原因
Node.js 20+版本对fs模块的文件权限处理逻辑做了变更:当通过fs.readFileSync以a+模式打开不存在的文件时,不再自动继承系统umask对应的默认文件权限,导致生成的文件权限为0000。而Node.js 18中a+模式创建文件时,会自动应用符合预期的默认权限(通常为0o644)。
解决方案
方案1:显式指定文件权限
在fs.readFileSync的配置中添加mode参数,明确指定文件的权限(例如0o644,代表所有者读写、组和其他用户只读):
import fs from 'fs' import path from 'path' import os from 'os' function modify(fsPath, key, value) { const dir = path.dirname(fsPath) if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }) // 显式指定mode参数,确保创建的文件拥有正确权限 let content = fs.readFileSync(fsPath, { encoding: 'utf8', flag: 'a+', mode: 0o644 }) content = content || '{}' const jsonContent = JSON.parse(content) jsonContent[key] = value fs.writeFileSync(fsPath, JSON.stringify(jsonContent), { encoding: 'utf8' }) } // 修正路径,匹配报错中的/test/foo.json const p = path.join(os.tmpdir(), 'test', 'foo.json') modify(p, 'key', 'foobar')
方案2:提前创建文件并设置权限
先判断文件是否存在,若不存在则先创建带正确权限的空文件,再进行读取操作:
import fs from 'fs' import path from 'path' import os from 'os' function modify(fsPath, key, value) { const dir = path.dirname(fsPath) if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }) // 提前创建文件(若不存在),确保权限正确 if (!fs.existsSync(fsPath)) { fs.writeFileSync(fsPath, '{}', { encoding: 'utf8', mode: 0o644 }) } const content = fs.readFileSync(fsPath, { encoding: 'utf8' }) const jsonContent = JSON.parse(content || '{}') jsonContent[key] = value fs.writeFileSync(fsPath, JSON.stringify(jsonContent), { encoding: 'utf8' }) } const p = path.join(os.tmpdir(), 'test', 'foo.json') modify(p, 'key', 'foobar')
方案3:替换文件打开模式
改用r+模式打开文件,但需提前确保文件存在(若不存在则先创建),避免r+模式下文件不存在时报错:
import fs from 'fs' import path from 'path' import os from 'os' function modify(fsPath, key, value) { const dir = path.dirname(fsPath) if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }) if (!fs.existsSync(fsPath)) { fs.writeFileSync(fsPath, '{}', { encoding: 'utf8' }) } // 使用r+模式读取文件 const content = fs.readFileSync(fsPath, { encoding: 'utf8', flag: 'r+' }) const jsonContent = JSON.parse(content || '{}') jsonContent[key] = value fs.writeFileSync(fsPath, JSON.stringify(jsonContent), { encoding: 'utf8' }) } const p = path.join(os.tmpdir(), 'test', 'foo.json') modify(p, 'key', 'foobar')
内容的提问来源于stack exchange,提问作者fannheyward
相关产品推荐
相关产品推荐

