Node.js 读写 JSON 文件:从基础到实践
在 Node.js 开发中,JSON(JavaScript Object Notation)因其轻量级、易读、与 JavaScript 原生兼容的特性,成为数据存储和交换的常用格式,无论是配置文件、数据缓存,还是 API 响应,读写 JSON 文件都是开发者必备的技能,本文将详细介绍 Node.js 中读写 JSON 文件的多种方法,包括同步/异步操作、错误处理及最佳实践,帮助你在实际项目中灵活应用。
读取 JSON 文件
Node.js 提供了多种读取文件的方式,核心模块 fs(File System)是基础选择,fs/promises(Promise 版本)和第三方库 fs-extra 也能简化操作,以下是具体实现:
使用 fs.readFileSync 同步读取
同步读取会阻塞代码执行,适合简单的脚本或小文件场景,代码直观易理解。
const fs = require('fs');
try {
// 读取 JSON 文件(需指定完整路径,相对路径基于执行命令的目录)
const jsonData = fs.readFileSync('./data.json', 'utf8');
// 将 JSON 字符串解析为 JavaScript 对象
const data = JSON.parse(jsonData);
console.log('读取成功:', data);
} catch (error) {
console.error('读取 JSON 文件失败:', error.message);
}
说明:
fs.readFileSync(path, options):第一个参数是文件路径,第二个参数'utf8'表示以 UTF-8 编码读取(默认为buffer)。JSON.parse():将 JSON 字符串转换为 JavaScript 对象,若文件内容不是合法 JSON,会抛出SyntaxError。try-catch:捕获文件不存在(ENOENT)或 JSON 解析错误,避免程序崩溃。
使用 fs.readFile 异步读取(回调方式)
异步读取不会阻塞主线程,适合 I/O 密集型应用(如读取大文件或高频读取),但回调方式可能导致“回调地狱”。
const fs = require('fs');
fs.readFile('./data.json', 'utf8', (err, jsonData) => {
if (err) {
console.error('读取 JSON 文件失败:', err.message);
return;
}
try {
const data = JSON.parse(jsonData);
console.log('读取成功:', data);
} catch (parseError) {
console.error('JSON 解析失败:', parseError.message);
}
});
说明:
- 回调函数的第一个参数是错误对象(
err),第二个参数是文件内容(jsonData)。 - 需同时处理文件读取错误和 JSON 解析错误,避免遗漏异常。
使用 fs/promises.readFile 异步读取(Promise 方式)
Node.js 提供了 fs/promises 模块,将 fs 的异步方法封装为 Promise,配合 async/await 可实现更清晰的异步代码。
const fs = require('fs/promises');
async function readJsonFile() {
try {
const jsonData = await fs.readFile('./data.json', 'utf8');
const data = JSON.parse(jsonData);
console.log('读取成功:', data);
} catch (error) {
console.error('读取 JSON 文件失败:', error.message);
}
}
readJsonFile();
说明:
fs.promises.readFile返回 Promise,可用await等待结果,避免回调嵌套。- 错误处理通过
try-catch集中管理,代码更简洁。
使用第三方库 fs-extra(推荐)
fs-extra 是 fs 的增强版,提供了更简洁的 API 和 Promise 支持,同时兼容原有 fs 方法,适合需要频繁文件操作的项目。
安装
npm install fs-extra
使用示例
const fs = require('fs-extra');
async function readJsonFile() {
try {
// 直接读取并解析 JSON,无需手动调用 JSON.parse
const data = await fs.readJson('./data.json');
console.log('读取成功:', data);
} catch (error) {
console.error('读取 JSON 文件失败:', error.message);
}
}
readJsonFile();
优势:
fs.readJson()内部封装了文件读取和 JSON 解析,代码更简洁。- 提供了更多实用方法(如
fs.existsSync、fs.outputJson),适合复杂场景。
写入 JSON 文件
写入 JSON 文件的核心是将 JavaScript 对象转换为 JSON 字符串,然后通过 fs 模块写入文件,同样支持同步/异步和多种实现方式。
使用 fs.writeFileSync 同步写入
同步写入会阻塞代码,适合需要立即确认写入结果的场景(如配置保存)。
const fs = require('fs');
const data = {
name: 'Node.js',
version: '18.17.0',
features: ['event-driven', 'non-blocking']
};
try {
// 将对象转换为 JSON 字符串(第二个参数格式化,第三个参数缩进空格数)
const jsonString = JSON.stringify(data, null, 2);
fs.writeFileSync('./data.json', jsonString, 'utf8');
console.log('JSON 文件写入成功');
} catch (error) {
console.error('写入 JSON 文件失败:', error.message);
}
说明:
JSON.stringify(obj, replacer, space):obj:要转换的对象。replacer:可选,过滤或转换属性(如数组['name', 'version']只保留这两个属性)。space:可选,格式化输出(数字表示缩进空格数,2表示美观缩进)。
- 写入时需确保目标目录存在(否则会抛出
ENOENT错误)。
使用 fs.writeFile 异步写入(回调方式)
异步写入适合非阻塞场景,如日志记录、批量数据处理。
const fs = require('fs');
const data = {
name: 'Node.js',
version: '18.17.0',
features: ['event-driven', 'non-blocking']
};
const jsonString = JSON.stringify(data, null, 2);
fs.writeFile('./data.json', jsonString, 'utf8', (err) => {
if (err) {
console.error('写入 JSON 文件失败:', err.message);
return;
}
console.log('JSON 文件写入成功');
});
使用 fs/promises.writeFile 异步写入(Promise 方式)
配合 async/await 实现更优雅的异步写入。
const fs = require('fs/promises');
async function writeJsonFile() {
const data = {
name: 'Node.js',
version: '18.17.0',
features: ['event-driven', 'non-blocking']
};
const jsonString = JSON.stringify(data, null, 2);
try {
await fs.writeFile('./data.json', jsonString, 'utf8');
console.log('JSON 文件写入成功');
} catch (error) {
console.error('写入 JSON 文件失败:', error.message);
}
}
writeJsonFile();
使用 fs-extra 写入 JSON
fs-extra 的 writeJson 方法直接支持对象写入,无需手动调用 JSON.stringify。
const fs = require('fs-extra');
async function writeJsonFile() {
const data = {
name: 'Node.js',
version: '18.17.0',
features: ['event-driven', 'non-blocking']
};
try {
// 直接写入对象,内部自动调用 JSON.stringify
await fs.writeJson('./data.json', data, { spaces: 2 });
console.log('JSON 文件写入成功');
} catch (error) {
console.error('写入 JSON 文件失败:', error.message);
}
}
writeJsonFile();
优势:
fs.writeJson()自动处理对象转字符串,减少代码量。- 支持更多选项(如
spaces格式化、flag文件标志),适合复杂写入需求。
进阶实践与注意事项
文件路径处理(推荐使用 path 模块)
硬编码相对路径可能导致路径错误(如在不同执行目录下运行脚本)。path 模块可帮助处理跨平台路径问题:
const fs = require('fs');
const path = require('path');
// 构建绝对路径(__dirname 表示当前脚本所在目录)
const filePath = path.join(__dirname, 'data.json');
try {
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
console.log('读取成功:', data);
} catch (error) {
console.error('读取失败:', error.message);
}
错误处理最佳实践
- 文件不存在:



还没有评论,来说两句吧...