fs模块
在nodejs中fs模块是进行文件的io操作的一个类,在这个模块下包含很多操作文件的api,具体内容直接去官网看API即可,接下来将讲解使用fs模块进行文件流的读取和写入操作
预备知识
首先在进行文件流的读写案例之前,我们需要知道几个常用的path的api:
- path.join() 路径拼接的
- path.resolve()也是路径拼接的,和path.join的唯一区别就是path.resolve是通过类似于cd的形式进行路径的拼接的
- __dirname 表示当前文件所在的目录的绝对路径(不包含当前执行的文件名)
- __filename 表示当前文件的绝对路径(包含当前执行文件名)
fs相关API
在这个案例中,我们需要提前知道一下几个API的用法:
-
fs.createReadStream
fs.createReadStream是创建文件可读流的一个API
参数1:string | buffer | url
参数2:options对象
const fs = require('fs');
const path = require('path');
// 源文件路径和目标文件路径
const sourceFilePath = path.join(__dirname, 'NN.pdf');
// 创建可读流
const readStream = fs.createReadStream(sourceFilePath);
// 监听 'data' 事件以更新进度
readStream.on('data', chunk => {
transferredBytes += chunk.length;
const percentTransferred = (transferredBytes / totalBytes) * 100;
process.stdout.clearLine(); // 清除当前行
process.stdout.cursorTo(0); // 将光标移动到行首
process.stdout.write(`传输进度: ${percentTransferred.toFixed(2)}%`);
});
// 错误处理
readStream.on('error', err => console.error('读取文件时出错:', err));
// 使用管道连接两个流
readStream.pipe(writeStream);
-
fs.createWriteStream
fs.createWriteStream 是创建可写流的一个API
参数:和可读流参数一致
const fs = require('fs');
const path = require('path');
// 源文件路径和目标文件路径
const destinationFilePath = path.join(__dirname, 'destination-large-file.txt');
// 创建可读流和可写流
const writeStream = fs.createWriteStream(destinationFilePath);
// 当所有数据被写入后触发
writeStream.on('finish', () => {
console.log('\n文件传输成功完成!');
});
// 错误处理
writeStream.on('error', err => console.error('写入文件时出错:', err));
// 使用管道连接两个流
readStream.pipe(writeStream);
-
fs.stat
fs.stat 是一个获取文件信息的API。该方法并不会读取整个文件内容,而是查询文件系统的元数据来获取文件信息。文件系统会为每个文件维护一些元数据,其中包括文件大小、创建时间、修改时间等信息。
fs.stat()只是请求这些已存在于文件系统中的元数据,因此它是一个非常快速和轻量级的操作,不会导致大量磁盘I/O。
const fs = require('fs');
const path = require('path');
// 源文件路径和目标文件路径
const sourceFilePath = path.join(__dirname, 'NN.pdf');
// 获取文件总大小
fs.stat(sourceFilePath, (err, stats) => {
if (err) throw err;
let totalBytes = stats.size;
});
其中stats参数是一个对象:
stats {
dev: 2114,
ino: 48064969,
mode: 33188,
nlink: 1,
uid: 85,
gid: 100,
rdev: 0,
size: 527, // 主要是这个参数,返回的是文件的字节大小
blksize: 4096,
blocks: 8,
atimeMs: 1318289051000.1,
mtimeMs: 1318289051000.1,
ctimeMs: 1318289051000.1,
birthtimeMs: 1318289051000.1,
atime: Mon, 10 Oct 2011 23:24:11 GMT,
mtime: Mon, 10 Oct 2011 23:24:11 GMT,
ctime: Mon, 10 Oct 2011 23:24:11 GMT,
birthtime: Mon, 10 Oct 2011 23:24:11 GMT }
- buffer对象
Buffer对象是Node处理二进制数据的一个接口。它是Node原生提供的全局对象,可以直接使用,不需要require('buffer')。- length 属性:length属性返回Buffer对象所占据的内存长度,返回值是xxx字节。
文件流案例
普通的文件流读取
const fs = require('fs');
const path = require('path');
// 源文件路径和目标文件路径
const sourceFilePath = path.join(__dirname, 'NN.pdf');
const destinationFilePath = path.join(__dirname, 'destination-large-file.txt');
// 创建可读流和可写流
const readStream = fs.createReadStream(sourceFilePath);
const writeStream = fs.createWriteStream(destinationFilePath);
// 获取文件总大小
fs.stat(sourceFilePath, (err, stats) => {
if (err) throw err;
let totalBytes = stats.size;
let transferredBytes = 0;
// 监听 'data' 事件以更新进度
readStream.on('data', chunk => {
// chunk是一个 buffer对象
transferredBytes += chunk.length;
const percentTransferred = (transferredBytes / totalBytes) * 100;
process.stdout.clearLine(); // 清除当前行
process.stdout.cursorTo(0); // 将光标移动到行首
process.stdout.write(`传输进度: ${percentTransferred.toFixed(2)}%`);
});
// 当所有数据被写入后触发
writeStream.on('finish', () => {
console.log('\n文件传输成功完成!');
});
// 错误处理
readStream.on('error', err => console.error('读取文件时出错:', err));
writeStream.on('error', err => console.error('写入文件时出错:', err));
// 使用管道连接两个流
readStream.pipe(writeStream);
});
在这个代码中,监听 'data' 事件以更新进度我们使用的是简单的展示效果。我们可以使用一个第三方库在控制台进行文件流进度展示,那这就需要使用cli-progress来进行操作啦。
使用cli-progress进行文件流进度可视化
/**
* 进阶版 :使用cli-progress进行可视化展示
*/
const fs = require('fs');
const path = require('path');
const cliProgress = require('cli-progress');
// create a new progress bar instance and use shades_classic theme
const bar1 = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
// 源文件路径和目标文件路径
const sourceFilePath = path.join(__dirname, 'NN.pdf');
const destinationFilePath = path.join(__dirname, 'destination-large-file.txt');
// 创建可读流和可写流
const readStream = fs.createReadStream(sourceFilePath);
const writeStream = fs.createWriteStream(destinationFilePath);
// 获取文件总大小
fs.stat(sourceFilePath, (err, stats) => {
if (err) throw err;
// 使用管道连接两个流
readStream.pipe(writeStream);
let totalBytes = stats.size;
let transferredBytes = 0;
bar1.start(totalBytes, 0);
// 监听 'data' 事件以更新进度
readStream.on('data', chunk => {
transferredBytes += chunk.length;
bar1.update(transferredBytes);
if (transferredBytes >= totalBytes) {
bar1.stop();
}
});
// 当所有数据被写入后触发
writeStream.on('finish', () => {
console.log('\n文件传输成功完成!');
});
// 错误处理
readStream.on('error', err => console.error('读取文件时出错:', err));
writeStream.on('error', err => console.error('写入文件时出错:', err));
});
最后实现的效果如下:
引用
node 操作文件流 fs 同步与异步 流式文件的写入与读取