NodeJS提供了fs
核心模块,用于文件流读写、文件目录操作等,下面简单展示一些常用的例子代码。
fs.readFileSync()
和fs.writeFileSync()
使用同步的方式读写文件,下面是一个例子。
const fs = require("fs");
const txt1 = fs.readFileSync("./a.txt", "utf8");
console.log(txt1);
const txt2 = "你好";
fs.writeFileSync("./b.txt", txt2);
这里要注意,我们知道NodeJS中JavaScript脚本是单线程运行的,使用同步的方式读写较大的文件会导致程序阻塞,因此在NodeJS中极少使用上面的写法,通常使用异步方式读写文件。
fs.readFile()
和fs.writeFile()
使用异步的方式读写文件,下面是一个例子。
const fs = require("fs");
fs.readFile("a.txt", "utf8", function(err, data) {
fs.writeFile("b.txt", data, "utf8", function(err) {
console.log("write finished");
});
});
console.log("test");
输出结果如下:
test
write finished
上面代码中以异步方式读写文件,和同步方式的区别就是异步方式中,我们需要传入回调函数(callback)作为参数,回调函数会在读或写完成时被调用,实际的IO操作和主线程是异步的。
上文使用的fs.readFile()
、fs.writeFile()
等函数都是一次性把文件读入内存或是写入文件,对于很大的文件或是网络程序,这种做法肯定是不行的。这种情况下,我们通常使用流和一个缓冲区对数据进行操作。
下面例子代码中,我们使用流读写一个大文件。
const fs = require("fs");
const readStream = fs.createReadStream("a.exe");
const writeStream = fs.createWriteStream("b.exe");
//输入流读入buffer,并立刻写到输出流
readStream.on("data", function(buffer) {
writeStream.write(buffer);
});
readStream.on("end", function() {
console.log("read finished");
//当输入流读完关闭输出流
writeStream.end();
});
writeStream.on("finish", function() {
console.log("write finished");
});
在Linux的bash中,我们经常使用ls | grep pattern
这样的管道操作,ls
命令的输出被对接到了grep
程序的输入流上,NodeJS中的管道也是类似的概念,我们可以把一个流对接到另一个流上,实现数据的转运。下面是使用pipe
实现文件复制的例子。
const fs = require("fs");
const readStream = fs.createReadStream("a.exe");
const writeStream = fs.createWriteStream("b.exe");
//使用管道进行数据转运
readStream.pipe(writeStream);
readStream.on("end", function() {
console.log("read finished");
writeStream.end();
});
writeStream.on("finish", function() {
console.log("write finished");
});
通过前面内容我们可以看到,fs
模块的API大多是以回调函数的形式提供的,而非原生支持Promise
,这也导致难以用上JavaScript最新的async/await
语法,在老的版本中我们必须自己封装返回Promise
的方法,或是使用内置的promisify
函数等。
然而,这一状况从node 14版本开始得到了改善,这一版本引入了fs/promises
模块,它的API和原版的fs
基本一致,但其返回值为Promise
,我们可以使用async/await
写法调用这些API,并使用try/catch
捕获异常。
有关fs/promises
的内容这里就不展开介绍了,用法和原版的fs
基本一致,具体参考文档即可。