fs模块是Node.js模块核心模块之一,提供了符合POSIX规范的操作文件和目录的基本方法。这些方法都有异步和同步两种形式。在I/O操作密集型的应用中,推荐使用异步调用方式,以避免整个应用程序的阻塞。
所有异步方法的回调函数中第一个参数都是一个IO错误对象:
/**同步调用方法***/
const fs=require('fs');
fs.unlinkSync('/f2');
console.log('succ');
/**异步调用方法**/
const fs=require('fs');
fs.unlink('/f1',(err)=>{
if(err)throw err;
console.log('succ');
})
文件模式
类Unix文件系统中,针对文件和目录的操作,为了控制不同用户不同权限,定义了如下的操作权限:
r:Read,读取权限,对应数字为4
w:Write,写出权限,对应数字为2
x:eXecute,执行权限,对应数字为1
不同的用户又分为如下三种类型:
u:User,文件所有者
g:Group,文件所有者所在组的其他成员
o:Other,其他用户
-rwx------ 700 文件所有者对文件具有读取、写入和执行的权限。
-rwxr--r-- 744 文件所有者具有读、写与执行权限,其他用户则具有读取的权限。
-rw-rw-r-- 664 文件所有者与同组用户对文件具有读写的权限,而其他用户具有读取的权限
drwx--x--x 711 目录所有者具有读写与进入目录的权限,其他用户只能进入该目录。
常用class
class名 | 说明 |
---|---|
fs.Stats | 文件或目录的统计信息描述对象 |
fs.ReadStream | stream.readable接口的实现对象 |
fs.WriteStream | stream.Writeable接口实现对象 |
fs.FSWatcher | 可用于监视文件修改的文件监视器对象 |
常用方法
方法名 | 说明 |
---|---|
fs.mkdir() | 创建目录 |
fs.rmdir() | 删除目录 |
fs.readFile() | 读取文件内容 |
fs.writeFile() | 向文件写出内容 |
fs.apendFile() | 向文件追加内容 |
fs.unlink() | 删除文件 |
fs.rename() | 重命名文件 |
文件信息统计
fs.stat( )和fs.statSync( )方法用于返回一个文件或目录的统计信息对象(fs.Stats类型)。
const fs=require('fs');
fs.stat("./app.log",(err,stats)=>{
if(err) throw err;
console.log(stats);
console.log(stats.isFile())
})
/****输出获取到的信息*******/
{
dev: 1786362065,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
blksize: 4096,
ino: 1407374883658375,
size: 12,
blocks: 0,
atimeMs: 1572344727794.7805,
mtimeMs: 1572344727414.4744,
ctimeMs: 1572344727414.4744,
birthtimeMs: 1572344727413.4426,
atime: 2019-10-29T10:25:27.795Z,
mtime: 2019-10-29T10:25:27.414Z,
ctime: 2019-10-29T10:25:27.414Z,
birthtime: 2019-10-29T10:25:27.413Z
}
true
fs.Stats对象还提供了如下方法可用于检查文件的物理特性:
方法名 | 说明 |
---|---|
stats.isFile() | 是否为文件 |
stats.isDireCtory() | 是否为目录 |
stats.isBlockDevice() | 是否为块设备,如磁盘 |
stats.isCharacterDevice() | 是否为字符设备,如键盘 |
stats.isFIFO() | 是否为FIFO设备,如打印机 |
stats.isSocket() | 是否为Socket文件 |
const path='./htdocs';
fs.stat(path,(err,stats)=>{
if(err){
fs.mkdir(path);
}else{
fs.readdir(path,(err,list)=>{
console.log(list)
})
}
})
操作目录
方法名 | 说明 |
---|---|
fs.mkdir(path[,mode],callback) | 创建指定目录(mode就是文件权限) |
fs.mkdirSync(path[,mode]) | 创建指定目录 |
fs.rmdir(path,callback) | 删除指定目录 |
fs.rmdirSync(path) | 删除指定目录 |
fs.readdir(path[,options],callback) | 读取目录下内容 |
fs.readdirSync(path[,options]) | 读取目录下内容 |
创建一个htdocs目录,当前用户、当前用户所在分组其他成员、其他成员具有读写和执行的权限:
const fs=require('fs');
fs.mkdir('./htdocs',777,(err)=>{
if(err)throw err;
console.log("目录创建成功!");
})
读取htdocs目录下的内容:
fs.readdir("./htdocs",(err,list)=>{
if(err)throw err;
console.log(list);
});
//[ 'img','index.html' ]
删除htdocs目录下的img文件夹:
fs.rmdir('./htdocs/img',(err)=>{
if(err) throw err;
console.log("目录删除成功!")
})
读写文件全部内容
对于数据量不是很大的文件,可以一次性的读写其中的全部内容。
方法名 | 说明 |
---|---|
fs.readFile(file[,options],callback) | 读取文件内容 |
fs.writeFile(file,data[,options],callback) | 写出内容 |
fs.apendFile(file,data[,options],callback) | 追加内容 |
读取文件内容:
const path='./htdocs/index.html';
fs.readFile(path,(err,data)=>{
if(err)throw err;
console.log(data);
console.log(data.toString())
})
向文件写出内容:
const path='./htdocs/index.html';
var data="<h1>你好世界!</h1>"
fs.writeFile(path,data,(err)=>{
if(err)throw err;
console.log("写入数据完成!");
})
注意:若文件不存在,则writeFile方法会自动创建该文件;若目标文件存在,该方法会覆盖原有所有内容。
向文件追加内容:
const path='./htdocs/index.html';
var data="<h2>我很好!</h2>"
fs.appendFile(path,data,(err)=>{
if(err)throw err;
console.log("追加数据完成!");
})
注意:若目标文件不存在,则appendFile方法会自动创建该文件;若目标文件存在,该方法会在原来内容后面追加新内容。
读写文件部分内容
腹泻文件的部分内容,需要安装如下步骤:
(1)打开指定文件,获取对应的"文件描述符(File Descriptor)"
(2)读取或写入文件指定部分的内容;
(3)关闭文件待其他进程使用。
方法名 | 说明 |
---|---|
fs.open(path[,mode],callback) | 打开文件 |
fs.read(fd,buffer,offset,length,potion,callback) | 读取文件(offset是buffer的存储偏移量,length是buffer存储数据最大长度,option从文件内开始读取的位置) |
fs.write(fd,offset,length[,position],callback) | 写出文件 |
fs.close(fd,callback) | 关闭文件 |
读取市部分内容:
const src='./htdocs/index.html';
fs.open(src,(err,fd)=>{
if(err)throw err;
const buf=Buffer.alloc(1024);
fs.read(fd,buf,0,1024,0,(err,bytesRead,buffer)=>{
if(err)throw err;
console.log("实际读取道德字节数:%d",bytesRead);
console.log(buffer.toString('UTF-8',0,bytesRead));
fs.close(fd,(err)=>{
if(err)throw err;
console.log('文件已关闭!')
});
})
});
//45
//<h1>你好世界!</h1><h2>我很好!</h2>
//文件已关闭!
写入部分内容:
const src='./htdocs/index.html';
fs.open(src,'w',(err,fd)=>{
if(err)throw err;
const buf=Buffer.from("<h3>真好!</h3>");
fs.write(fd,buf,0,'UTF-8',(err,bytesRead,string)=>{
if(err)throw err;
console.log("写入部分内容成功!");
console.log("写入字节数为:%d,写入内容为:%s",bytesRead,string)
fs.close(fd,(err)=>{
if(err)throw err;
console.log('文件已关闭!')
});
})
});
//写入部分内容成功!
//写入字节数为:18,写入内容为:<h3>真好!</h3>
//文件已关闭!
文件的流式操作
流(Stream),是一组有序的,有起点和终点的字节或字符集数据的集合。
Node.js中,stream模块中的Readable接口的实现对象都可以来读取文件中的部分数据暂存在缓冲区中,如:fs.ReadStream、http.IncomingMessage、net.Socket、process.stdin等;这些对象都继承了EventMitter类,在读取数据过程中,可以触发各种流读取相关事件。
stream模块中的Writable接口的实现对象都可以用来写出数据到缓冲区中,待缓冲区满后向物理介质输出:fs.WriteStream、http.ClienrRequest、http.ServerResponse、net.Socket、process.stdout等;这些对象都继承了EventMitter类,在写出数据过程中,可以触发各种数据写出取相关事件。
输入流对象
stream.Readable对象可以触发下列事件:
事件名 | 说明 |
---|---|
readable | 当可以从流中读取数据时触发 |
data | 当读取到数据时触发 |
end | 当读取到流结尾时触发 |
error | 当出现读取错误时触发 |
close | 当流关闭时触发 |
stream.Readable对象可以执行如下操作:
方法名 | 说明 |
---|---|
read() | 读取数据 |
setEncoding() | 设置字符编码 |
pause() | 暂停读取 |
resume() | 继续读取 |
pipe() | 设置一个数据通道 |
unpipe() | 取消设置的数据通道 |
const fs=require('fs');
var read=fs.createReadStream('./htdocs/1.mp4');
var total=0;
read.on("data",(buf)=>{
console.log("数据长度:%d",buf.length);
total+=buf.length;
})
read.on("end",(err)=>{
if(err)throw err;
console.log("文件读取结束!");
console.log("读取到总字节数:%d",total);
})
read.on("close",(err)=>{
if(err)throw err;
console.log("流成功关闭!")
})
//数据长度:65536
//数据长度:65536
//...
//数据长度:65536
//数据长度:65536
//数据长度:65536
//数据长度:50848
//文件读取结束!
//读取到总字节数:117819040
//流成功关闭!
输出流对象
stream.Writeable对象可以触发下列事件:
事件名 | 说明 |
---|---|
drain | 当输出缓冲区已经排空时触发 |
finish | 当end()方法吧所有数据写出到缓冲区时触发 |
pipe | 当用于读取数据的对象调用pipe()时触发 |
unpipe | 当用于读取数据的对象调用unpipe()时触发 |
error | 当输出过程产生错误时触发 |
stream.Writeable对象可以执行如下操作:
方法名 | 说明 |
---|---|
write() | 写出数据 |
end() | 当没有更多数据需要再被输出时调用,此方法将清空输出缓冲区 |
使用readStream和writeStream实现一个文件拷贝功能:
const fs=require('fs');
var read=fs.createReadStream('./htdocs/1.mp4');
var write=fs.createWriteStream("./htdocs/1_copy.mp4");
var total=0;
read.on("data",(buf)=>{
console.log("数据长度:%d",buf.length);
total+=buf.length;
write.write(buf,0,buf.length);
})
read.on("end",(err)=>{
if(err)throw err;
console.log("文件读取结束!");
console.log("读取到总字节数:%d",total);
write.end();
});
read.on("close",(err)=>{
if(err)throw err;
console.log("流成功关闭!")
})
write.on("finish",(err)=>{
if(err)throw err;
console.log("文件写出完成!")
})
//数据长度:65536
//...
//数据长度:50848
//文件读取结束!
//读取到总字节数:117819040
//文件写出完成!
//流成功关闭!
使用管道
Pipe:管道,可以用于自动的去读一个Readable对象中的所有数据,并写出到指定的Writeable对象中。
const fs=require("fs");
const src="./htdocs/index.html";
const dest="./backup/index.html";
var read=fs.createReadStream(src);
var write=fs.createWriteStream(dest);
read.pipe(write); //使用管道实现自动读写
reader.on("end",(err)=>{
if(err)throw err;
console.log("文件已经复制完成!")
})