Node.js 文件系统操作
Posted YuLong~W
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js 文件系统操作相关的知识,希望对你有一定的参考价值。
文件系统基础
fs 模块
fs模块提供一组文件操作API用于模仿标准POSIX函数与文件系统进行交互。导入该模块:
const fs = require('fs');
fs模块共有5个类:
- fs.Dirent(指示文件类型)
- fs.FSWatcher(监视文件)
- fs.ReadStream(读取流)
- fs.WriteStream(写入流)
- fs.Stats(文件的信息)
名称具有 ‘Sync’ 后缀的方法为同步方法,不具有该后缀的方法为异步方法
fs模块支持FS常量,包括 文件可访问性、文件复制、文件打开、文件类型和文件模式的常量。
同步、异步文件操作
- fs模块包含同步文件操作和异步文件操作两大类API方法,大多数文件操作提供同步和异步两种方式
- 异步操作方法或函数的最后一个参数总是一个回调函数
- 异步操作方法支持同时处理多个任务,阻塞少、性能高、速度快
- 同步操作将阻塞整个进程,直到所有任务完成
- 注意异步函数执行顺序
//异步读取文件
fs.readFile('\\world.txt',(err,data )=>{
if (err){
console.log(err);
}
console.log('文件内容是',data.toString());
})
console.log('主程序结束');
//执行结果:
//文件内容是:...
//主程序结束
//同步读取文件
var data=fs.readFileSync('\\world.txt');
console.log(data.toString());
console.log('主程序结束了');
//执行结果:
//主程序结束
//文件内容是:...
文件路径
1、文件路径表示方法:
2、path模块处理路径的方法:
描述 | 方法 |
---|---|
获取目录名 | path.dirname(path) |
获取扩展名 | path.extname(path) |
规范化路径 | path.normalize(path) |
解析路径 | path.resolve([…paths]) |
连接路径 | path.join([…paths]) |
文件模式
文件模式即文件访问权限,fs模块遵循POSIX文件操作规范
文件描述符:
- 操作系统为每个打开的文件分配一个名为文件描述符的数字,文件操作使用这些文件描述符来识别与追踪每个特定的文件
- 在Node.js中每操作一个文件,文件描述符都是会自动递增的,文件描述符一般从 3 开始
fs.open()
方法用于分配新的文件描述符。一旦被分配,文件描述符可用于从文件读取数据、向文件写入数据或请求关于文件的信息- 大多数操作系统会限制在任何给定时间内可能打开的文件描述符的数量,因此操作完成时关闭描述符至关重要
fs.open('\\world.txt','r+',(err,fd) =>{
if (err){
throw err;
}
console.log('文件操作符是:',fd);
} )
//执行结果: 文件操作符是: 3
文件与目录基本操作
文件基本操作
1、打开文件:
- 异步打开文件的用法:
fs.open(path, flags[, mode], callback)
- 同步打开文件的用法:
fs.openSync(path, flags[, mode])
异步方式打开文件示例:
const fs = require('fs');
console.log("准备打开文件");
//r+表示以读写模式打开,fd为返回的文件描述符
fs.open('demo.txt', 'r+', function(err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打开成功!");
});
2、获取文件信息:
异步方式获取文件信息的用法:fs.stat(path[, options], callback)
fs.Stats类提供的方法:
fs.stat("\\world.txt", function (err, stats) {
if(err) throw err;
console.log(stats);//显示返回的fs.Stats对象
console.log("读取文件信息成功!");
// 检测文件类型
console.log("是否为文件? " + (stats.isFile() ? '是':'否'));
console.log("是否为目录? " + (stats.isDirectory() ? '是':'否'));
// 读取文件属性
console.log("文件大小:" + stats.size);
console.log("创建时间:" + stats.birthtime);
});
3、读取文件:
异步方式读取文件指定数据的用法:fs.read(fd, buffer, offset, length, position, callback)
const fs = require('fs');
fs.open("\\demo.txt","r",function(err,fd)
{
if(err) throw err;
console.log("打开文件成功。");
var buf = Buffer.alloc(24);//分配缓冲区
//开始读取字节
fs.read(fd,buf,0,buf.length,0,function(err,bytes) {
if(err){
fs.closeSync(fd);//关闭文件
return console.log(err);
}
console.log("读取的字节长度:"+bytes);
// 仅输出读取的字节
if(bytes > 0){
console.log("打开文件后读取的buff内容:"+buf.slice(0, bytes).toString());
}
fs.closeSync(fd);//关闭文件
});
});
异步方式读取文件全部内容的用法:fs.readFile(path[, options], callback)
const fs = require("fs");
fs.readFile('\\demo.txt', (err, data) => {
if (err) throw err;
console.log(data);
});
读取GBK格式的文件:
const fs = require('fs');
const iconv = require('iconv-lite'); // 加载编码转换模块
fs.readFile('gbksample.txt', function(err, data){
if (err) throw err;
console.log(data); // 输出字节数组
var text = iconv.decode(data, 'gbk'); // 把数组转换为gbk中文
console.log(text); // 输出中文内容
//按默认的UTF8字符编码写入
fs.writeFile('utf8sample.txt',text, function(err){
if (err) throw err;
});
});
4、写入文件:
异步方式 覆盖式 写入文件的用法:fs.writeFile(file, data[, options], callback)
异步方式 追加式 写入文件的用法:fs.appendFile(path, data[, options], callback)
将数据写入文件 指定的位置:
- 写入 Buffer对象 的用法:
fs.write(fd, buffer[, offset[, length[, position]]], callback)
- 写入 字符串 的用法:
fs.write(fd, string[, position[, encoding]], callback)
5、文件的其他操作:
目录的基本操作
1、创建目录:
异步创建目录的用法:fs.mkdir(path[, options], callback)
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
if (err) throw err;
});
2、删除目录:
异步删除目录的用法:fs.rmdir(path, callback)
3、读取目录内容:
异步读取目录内容的用法:fs.readdir(path[, options], callback)
const fs= require('fs');
console.log("查看上一级目录的内容");
fs.readdir("../",function(err, files){
if (err) throw err;
files.forEach( function (file){
console.log( file );
});
});
文件系统高级操作
流接口
1、从流中读取数据:
创建一个可读流的用法:fs.createReadStream(path[, options])
通过流接口读取文件内容的示例:
const fs = require('fs');
var data = '';
var readStream = fs.createReadStream('demo.txt'); // 创建可读流
readStream.setEncoding('UTF8'); // 设置字符编码格式为 utf8
//以下处理流事件data(当有数据可读时触发)、end(无数据可读时触发)和 error(发生错误时触发)
readStream.on('data', (chunk) => {
data += chunk;
});
readStream.on('end', () =>{
console.log(data);
});
readStream.on('error', (err) => {
console.log(err.stack);
});
2、将数据写入流:
创建一个可写流的用法:fs.createWriteStream(path[, options])
3、流的管道操作:
const fs= require('fs');
var readStream = fs.createReadStream('src_file');//打开源文件准备读取
var writeStream = fs.createWriteStream('dest_file');//使用新的数据覆盖目标文件
readStream.pipe(writeStream); //从源文件读取时,将读取的数据写入到目标文件
4、流的链式操作:
压缩文件示例:
const fs= require('fs');
const zlib = require('zlib');
fs.createReadStream('demo.txt')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('demo.txt.gz'));
console.log("文件压缩完成!");
解压缩文件示例:
const fs= require('fs');
const zlib = require('zlib');
fs.createReadStream('demo.txt.gz')
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream('demo.txt'));
console.log("文件解压缩完成!");
文件遍历和监视
文件遍历
- 使用 fs.readdir() 方法获取目录下的文件列表。
- 遍历此文件列表,并使用 fs.stat() 方法获取文件信息。
- 根据获取的信息判断是文件还是目录。
- 如果是文件,打印其绝对路径。
- 如果是目录,返回第1步重新从开始获取文件列表直至第5步操作。由于目录级数未知,所以可以使用递归方法来解决。
文件遍历示例:
const fs = require('fs');
const path = require('path');
var filePath = path.resolve('../');//这里遍历的是上一级目录
fileTraverse (filePath); //调用文件遍历函数
/*定义文件遍历函数,参数filePath是需要遍历的文件路径 */
function fileTraverse (filePath){
//根据文件路径读取文件,返回文件列表
fs.readdir(filePath,function(err,files){
if(err){
console.warn(err)
}else{
//遍历读取到的文件列表
files.forEach(function(file){
var fullPath = path.join(filePath,file); //获取当前文件的绝对路径
//根据文件路径获取文件信息,返回一个fs.Stats对象
fs.stat(fullPath,function(eror,stats){
if(eror){
console.warn('获取文件信息失败');
}else{
if(stats.isFile()){ //如果是文件
console.log(fullPath);
}
if(stats.isDirectory()){//如果是目录
fileTraverse (fullPath);//递归,继续遍历该目录下的文件
}
}
})
});
}
});
}
文件监视
1、fs.watch() 用法:fs.watch(filename[, options][, listener])
示例:监听上一级目录下文件变化
const fs = require('fs');
fs.watch('../', (eventType, filename) => {
if (eventType=='rename'){
console.log('发生重命名');
}
if (eventType=='change'){
console.log('发生修改');
}
if (filename) {
console.log(`文件名: ${filename}`);
} else {
console.log('文件名未提供');
}
});
2、fs.watchFile() 用法:fs.watchFile(filename[, options], listener)
示例:监听某文件变化
const fs = require('fs');
//每隔1秒时间检测文件变化
fs.watchFile('demo.txt', {interval: 1000}, function (curr, prev) {
console.log('当前的文件修改时间:' + curr.mtime + '当前的文件大小:' + curr.size);
console.log("上一次文件修改时间:" + prev.mtime + '之前的文件大小:' + prev.size);
fs.unwatchFile('demo.txt'); // 停止监听
});
选择fs.watch()还是fs.watchFile():
- fs.watch()方法更高效,但其API在各个平台上并非完全一致,在某些情况下不可用
- 如果底层功能由于某些原因不可用,则fs.watch()方法将无法运行。此时就要考虑选用fs.watchFile()方法
- fs.watchFile()方法较慢且不太可靠,但它是跨平台的,因而在网络文件系统中更可靠
JSON格式文件操作
1、从JSON文件中读取数据:
const fs = require('fs');
fs.readFile('person.json',function(err,data){
if(err) throw err;
var person =JSON.parse(data.toString());//将字符串转换为JSON对象
//对JSON数据进行处理
for(var i = 0; i < person.length;i++){
console.log('姓名:'+ person[i].name +' 年龄:'+ person[i].ages );
}
});
2、往JSON文件中添加数据:
const fs = require('fs');
var newobj = { "name":"刘强", "ages":21 }
fs.readFile('person.json',function(err,data){
if(err) throw err;
var person =JSON.parse(data.toString());//将字符串转换为JSON对象
person.push(newobj);//将新的对象加到数组对象中
var str = JSON.stringify(person); //将JSON对象转换成字符串重新写入JSON文件中
fs.writeFile('person.json',str, function(err) {
if(err) throw err;
console.log("数据写入成功!");
});
});
3、更改JSON文件中的指定数据:
for(var i = 0; i < person.length;i++){
if(person[i].name == '张红'){
person[i].ages = 22;
break;
}
}
var str = JSON.stringify(person); //将JSON对象转换成字符串重新写入JSON文件中
以上是关于Node.js 文件系统操作的主要内容,如果未能解决你的问题,请参考以下文章