Node.js文件操作核心是fs模块,推荐使用异步API避免阻塞事件循环。常用方法包括fs.readFile/writeFile进行异步读写,fs.readFileSync/writeFileSync用于同步场景(如配置加载),大文件处理应使用fs.createReadStream/writeStream流式操作以节省内存,配合pipe实现高效传输。路径处理需用path.join(__dirname, ...)确保跨平台兼容,权限问题可通过fs.access检查,避免EACCES错误。异步非阻塞模式是最佳实践。

Node.js在文件读写方面,核心就是利用其内置的
fs
*Sync
在Node.js中进行文件读写,最直接的方式就是通过
fs
读取文件:
最常见的读取文件方式是使用
fs.readFile()
fs.readFileSync()
异步读取 (fs.readFile
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'example.txt'); // 假设文件在当前目录下
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
console.error('读取文件时发生错误:', err);
// 这里可以根据错误类型做进一步处理,比如文件不存在、权限问题等
return;
}
console.log('异步读取到的内容:', data);
});
// 也可以使用Promise/async-await模式,代码会更现代和易读
const util = require('util');
const readFilePromise = util.promisify(fs.readFile);
async function readMyFile() {
try {
const data = await readFilePromise(filePath, 'utf8');
console.log('Async/Await 读取到的内容:', data);
} catch (err) {
console.error('Async/Await 读取文件时发生错误:', err);
}
}
readMyFile();这里我用了
path.join
同步读取 (fs.readFileSync
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'example.txt');
try {
const data = fs.readFileSync(filePath, 'utf8');
console.log('同步读取到的内容:', data);
} catch (err) {
console.error('同步读取文件时发生错误:', err);
// 记得处理错误,否则程序可能会崩溃
}写入文件:
写入文件同样有异步的
fs.writeFile()
fs.writeFileSync()
异步写入 (fs.writeFile
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'output.txt');
const content = '这是要写入文件的新内容。\nNode.js文件操作真有趣!';
fs.writeFile(filePath, content, 'utf8', (err) => {
if (err) {
console.error('写入文件时发生错误:', err);
return;
}
console.log('文件异步写入成功!');
});
// 同样可以Promise化
const writeFilePromise = util.promisify(fs.writeFile); // util在上面已经引入
async function writeMyFile() {
try {
await writeFilePromise(filePath, '这是通过Async/Await写入的内容。', 'utf8');
console.log('Async/Await 文件写入成功!');
} catch (err) {
console.error('Async/Await 写入文件时发生错误:', err);
}
}
writeMyFile();同步写入 (fs.writeFileSync
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'output_sync.txt');
const content = '这是通过同步方式写入的内容。';
try {
fs.writeFileSync(filePath, content, 'utf8');
console.log('文件同步写入成功!');
} catch (err) {
console.error('同步写入文件时发生错误:', err);
}追加内容 (fs.appendFile
fs.appendFileSync
appendFile
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'log.txt');
const newLogEntry = `\n[${new Date().toISOString()}] 用户访问记录。`;
fs.appendFile(filePath, newLogEntry, 'utf8', (err) => {
if (err) {
console.error('追加内容时发生错误:', err);
return;
}
console.log('内容已成功追加到文件。');
});这是一个老生常谈但又极其重要的问题,尤其是在Node.js这种单线程、事件驱动的环境里。我的经验是,绝大多数情况下,你都应该优先选择异步操作。
Node.js的核心优势在于其非阻塞I/O模型。当你的代码执行一个异步文件操作(比如
fs.readFile
想象一下,如果你的Web服务器在处理每个文件请求时都使用同步操作,那么当一个用户请求一个大文件时,其他所有用户的请求都必须排队等待,直到这个大文件完全读取完毕。这显然是不可接受的,用户体验会非常糟糕。
那么,同步操作就一无是处了吗?也不是。在一些特定的场景下,同步操作反而能让代码逻辑更简单,更直观。例如:
即便如此,我仍然建议你对同步操作保持警惕。即使是小的文件,在极端高并发或资源受限的环境下,也可能成为性能瓶颈。养成使用异步的习惯,能让你在项目规模扩大时少走很多弯路。
当我们谈到读写大文件时,
fs.readFile
fs.writeFile
这时候,Node.js的流(Stream)就闪亮登场了。流的理念是:数据不是一次性全部处理,而是以小块(chunks)的形式流动。你可以从一个流中读取数据,处理后,再写入另一个流。这就像水管一样,水(数据)在管道中持续流动,而不是先装满一个大桶再倒到另一个大桶。
流的优势:
pipe()
实践:使用fs.createReadStream
fs.createWriteStream
读取大文件:
fs.createReadStream(path, [options])
const fs = require('fs');
const path = require('path');
const bigFilePath = path.join(__dirname, 'big_file.txt'); // 假设这是一个大文件
const readStream = fs.createReadStream(bigFilePath, { encoding: 'utf8', highWaterMark: 64 * 1024 }); // highWaterMark设置缓冲区大小
let totalChunks = 0;
let totalSize = 0;
readStream.on('data', (chunk) => {
totalChunks++;
totalSize += chunk.length;
// console.log(`接收到数据块 (${chunk.length} 字节):`, chunk.substring(0, 50), '...');
// 这里你可以对每个数据块进行处理
});
readStream.on('end', () => {
console.log(`大文件读取完毕。总共接收了 ${totalChunks} 个数据块,总大小 ${totalSize} 字节。`);
});
readStream.on('error', (err) => {
console.error('读取大文件时发生错误:', err);
});写入大文件:
fs.createWriteStream(path, [options])
const fs = require('fs');
const path = require('path');
const outputFilePath = path.join(__dirname, 'copied_big_file.txt');
const writeStream = fs.createWriteStream(outputFilePath, { encoding: 'utf8' });
// 我们可以模拟一些数据写入
for (let i = 0; i < 100000; i++) {
writeStream.write(`这是第 ${i} 行模拟数据,用于测试大文件写入。\n`);
}
writeStream.end(() => {
console.log('大文件模拟写入完成。');
});
writeStream.on('error', (err) => {
console.error('写入大文件时发生错误:', err);
});流的管道(Piping):复制大文件 流最强大的地方在于它的
pipe()
const fs = require('fs');
const path = require('path');
const sourceFilePath = path.join(__dirname, 'big_file.txt');
const destinationFilePath = path.join(__dirname, 'big_file_copy.txt');
const readStream = fs.createReadStream(sourceFilePath);
const writeStream = fs.createWriteStream(destinationFilePath);
readStream.pipe(writeStream); // 一行代码搞定文件复制
readStream.on('error', (err) => {
console.error('复制过程中读取文件失败:', err);
});
writeStream.on('error', (err) => {
console.error('复制过程中写入文件失败:', err);
});
writeStream.on('finish', () => {
console.log('大文件复制完成!');
});使用流处理大文件是Node.js中非常高效且优雅的解决方案,它能让你轻松应对那些动辄几十上百兆,甚至更大的文件。
在Node.js中进行文件操作,除了API本身,最常让我头疼的,往往是文件路径和权限问题。这些问题看起来琐碎,但一旦出错,调试起来可能让人抓狂。
1. 文件路径的迷思:相对路径与绝对路径
相对路径: 在开发时我们经常使用
./data/config.json
process.cwd()
node src/app.js
app.js
./data/config.json
data
src
data
绝对路径: 避免这种混乱的最佳实践是使用绝对路径。Node.js提供了几个非常有用的全局变量和模块来帮助你构建可靠的绝对路径:
__dirname
__filename
path
path.join()
\
/
path.resolve()
示例:构建可靠的路径
const path = require('path');
// 获取当前脚本文件所在目录的绝对路径
const currentDir = __dirname;
console.log('当前脚本目录:', currentDir);
// 构建一个相对于当前脚本目录的data文件夹下的config.json的绝对路径
const configPath = path.join(currentDir, 'data', 'config.json');
console.log('配置文件的绝对路径:', configPath);
// 如果想获取项目根目录下的文件,可能需要向上跳几级
// 假设你的脚本在 project/src/utils/file_ops.js
// 项目根目录就是 path.resolve(__dirname, '..', '..')
const projectRoot = path.resolve(__dirname, '..'); // 假设当前脚本就在项目根目录的子目录
console.log('项目根目录:', projectRoot);我强烈建议你在任何需要引用文件的地方,都使用
path.join(__dirname, ...)
2. 权限问题:EACCES错误
当你尝试读写一个文件或目录,但你的Node.js进程没有足够的权限时,你会遇到
EACCES
Linux/macOS:
chmod
chmod
chmod 644 myfile.txt
chmod 777 mydir
chown
chown
www-data
Windows:
Node.js中的权限检查:fs.access()
fs.access()
const fs = require('fs');
const path = require('path');
const testFilePath = path.join(__dirname, 'test_permission.txt');
// 假设我们想检查文件是否存在且可写
fs.access(testFilePath, fs.constants.F_OK | fs.constants.W_OK, (err) => {
if (err) {
console.error(`文件 ${testFilePath} 不存在或不可写:`, err.message);
// 可能是 ENOENT (文件不存在) 或 EACCES (权限不足)
} else {
console.log(`文件 ${testFilePath} 存在且可写。`);
// 现在可以安全地进行写入操作了
fs.writeFile(testFilePath, 'Hello, world!', (writeErr) => {
if (writeErr) console.error('写入失败:', writeErr);
else console.log('文件写入成功。');
});
}
});处理权限问题,很多时候需要你在操作系统层面进行干预。当你在服务器上遇到
EACCES
以上就是怎样使用Node.js读写文件?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号