node内置模块——fs文件系统模块
文章目录文件系统的定义文件系统的重要作用fs模块同步和异步调用文件的写入文件的同步和异步写入打开文件向文件写内容保存并关闭简单文件写入文件进写入的特点文件的打开状态流式文件写入文件的读取同步文件读取异步文件读取简单文件读取流式文件读取流式文件实现文件的读取和写入传统写法简单写法fs的其他操作文件系统的定义文件系统:文件系统简单来说就是通过Node来操作系统中的文件 。文件系统的重要作用在Node中
文章目录
文件系统的定义
文件系统:文件系统简单来说就是通过Node来操作系统中的文件 。
文件系统的重要作用
在Node中,与文件系统的交互是非常重要的,服务器的本质就将本地的文件
发送给远程的客户端。
fs模块
Node通过fs模块
来和文件系统
进行交互。
fs模块
提供了一些标准文件访问API来打开、读取、写入文件,以及与其交互。
fs是核心模块,直接引入不需要下载。
var fs = require("fs")
同步和异步调用
fs模块中所有的操作都有两种形式可供选择同步和异步:
- 同步文件系统
会阻塞程序
的执行,也就是除非操作完毕,否则不会向下执行代码。 - 异步文件系统
不会阻塞程序
的执行,而是在操作完成时,通过回调函数
将结果返回。异步的方法都有回调函数
我们更常用的是异步方法。
目录的创建
创建目录
// 创建目录
fs.mkdir("./avatar", (err) => {
console.log(err)
if (err && err.code === 'EEXIST') {
console.log('目标已存在')
}
})
重命名目录
fs.rename("./avatar", "./avatar2", (err) => {
console.log(err)
if (err && err.code === 'ENOENT') {
console.log('目录不存在')
}
})
目录的删除
// 删除
fs.rmdir("./avatar2", err => {
console.log(err)
if (err && err.code === 'ENOENT') {
console.log('目录不存在')
}
})
如果目录不为空不会直接删除,要先删除文件才能删除目录。
目录的读取
fs.readdir("./avatar", (err, data) => {
if (!err) {
console.log(data)
}
console.log(err)
})
- 查看目录下文件的具体信息
fs.stat("./avatar", (err, data) => {
console.log(data)
})
fs.stat("./avatar", (err, data) => {
//是否是目录
console.log(data.isDirectory())
//是否是文件
console.log(data.isFile())
})
包含文件的目录的删除
- 同步删除
fs.readdir("./avatar", (err, data) => {
data.forEach(item => {
// 使用同步方法进行删除,以为嫩文件删除完才能删除目录
fs.unlinkSync(`./avatar/${item}`)
})
fs.rmdir("./avatar",(err)=>{console.log(err)})
})
同步问题:由于JS是单线程的所以一旦同步阻塞整个网页就卡在那里了。
- 异步删除——基于Promise
const fs = require("fs").promises
fs.readdir("./avatar2").then(async (data) => {
let arr=[]
data.forEach(item => {
arr.at.push(fs.unlink(`./avatar2/${item}`))
})
// Promise.all([]),等待数组中的内容都执行完才往下执行
await Promise.all(arr)
await fs.rmdir("./avatar2")
})
或者
const fs = require("fs").promises
fs.readdir("./avatar2").then(async (data) => {
await Promise.all(data.map(item=>fs.unlink(`./avatar/${item}`)))
await fs.rmdir("./avatar2")
})
所以关于文件的操作都有基于require("fs").promises
的另一种写法:
//读取文件
fs.readFile("./文件读取.js", "utf-8").then(data => {
console.log(data)
})
文件的写入
文件的同步和异步写入
打开文件
- 同步:
fs.openSync(path[, flags[, mode]])
path:要打开文件的路径
flags:打开文件要做的操作类型:r:只读,w:可写的
mode: 设置文件的操作权限,一般不传
该方法会返回一个文件的描述符
作为结果,我们可以通过该描述符来对文件进行各种操作。
var fs = require("fs")
var fd = fs.openSync('hello.txt', 'w')
console.log(fd)
输出:
3
3就是该文件的编号
- 异步:
fs.open(path[, flags[, mode]], callback)
callback是必须的。
异步调用的结果都是通过回调函数返回的,而不通过return返回。
我们一般取回调函数的参数arguments:err
:错误对象,如果没有错误则为nullfd
:文件的描述符
eg:
var fs = require("fs")
var fd = fs.open('hello.txt', 'w',function (err,fd){
if (!err) {
console.log(fd)
} else {
console.log(err)
}
})
输出:
3
异步的体现:
var fs = require("fs")
var fd = fs.open('hello.txt', 'w',function (err,fd){
if (!err) {
console.log("open done")
} else {
console.log(err)
}
})
console.log("after open")
输出:
after open
open done
我们发现先输出的after open,再输出open done。这就是因为服务器在下完open
的命令之后将open的过程交给其他线程,而自己继续向下执行,当open完成之后再执行回调函数,所以open done 在after open之后。
向文件写内容
- 同步:
fs.writeSync(fd, string[, position[, encoding]])
fd:要写入的文件位置+文件名
如果文件不存在会自动创建
string:要写入的内容
写入的内容默认会覆盖问文件原本的内容
position:写入的起始位置
encoding:写入的编码,默认utf-8
var fs = require("fs")
var fd = fs.openSync('./hello.txt', 'w')
fs.writeSync(fd,"天气真不错")
输出:
hello.txt
- 异步:
fs.write(fd, string[, position[, encoding]], callback)
用来异步写入文件。
var fs = require("fs")
var fd = fs.open('hello.txt', 'w',function (err,fd){
if (!err) {
// 进行写入
fs.write(fd,"这是异步写入的内容",function (err){
if (!err) {
console.log("写入成功")
}
})
} else {
console.log(err)
}
})
保存并关闭
如果文件不关闭会占用大量的内存.
- 同步:
fs.closeSync(fd)
fd:要关闭的文件的描述符
var fs = require("fs")
var fd = fs.openSync('./hello.txt', 'w')
fs.writeSync(fd, "天气真不错")
fs.closeSync(fd)
- 异步:
fs.close(fd[, callback])
var fs = require("fs")
var fd = fs.open('hello.txt', 'w',function (err,fd){
if (!err) {
// 进行写入
fs.write(fd,"这是异步写入的内容",function (err){
if (!err) {
console.log("写入成功")
}
// 关闭
fs.close(fd,function (err){
if (!err) {
console.log("文件关闭成功")
}
})
})
} else {
console.log(err)
}
})
输出:
写入成功
文件关闭成功
同步是人类的思维习惯,异步可以提升计算机的运行速度。
简单文件写入
- 同步:
fs.writeFileSync(file, data[, options])
file:要操作文件的路径
及文件名
data:要写入的数据
options:选项,可以对写入进行一些设置,一般省略
options一般是一个对象,有如下属性:
(1)encoding:默认=‘utf8’
(2)mode:默认=00666
(3)flag:默认=‘w’ ,控制文件的打开状态
r:读 ; w:写 ;a:追加
eg:
var fs = require("fs")
fs.writeFile("C:\\Users\\86198\\Desktophello.txt", "简单写入",{flag:"w"})
- 异步:
fs.writeFile(file, data[, options], callback)
callback:写入完成以后执行的函数
var fs = require("fs")
fs.writeFile("hello.txt", "简单写入", function (err) {
if (!err) {
console.log("写入成功")
}
})
不用再打开和关闭文件了。writeFile是对打开、写入和保存文件的封装。
文件追加写入
默认情况下像文件写入会直接覆盖原来的内容,可以使用追加方法appendFile
,向文件中追加内容。
fs.appendFile("./avatar/a.txt", "\nhello",(err)=> {
console.log(err)
})
文件写入的特点
即 w
模式的特点:打开文件用于写操作,如果不存在则创建,如果存在则覆盖文件原本内容
文件的打开状态
标识符 | 状态 |
---|---|
r | 读取文件,文件不存在则出现异常 |
r+ | 读写文件,文件不存在则出现异常 |
rs | 在同步模式下打开文件用于读取 |
rs+ | 在同步模式下打开文件用于读写 |
w | 打开文件用于写操作,如果不存在则创建,如果存在则截断 |
wx | 打开文件用于写操作,如果存在则打开失败 |
w+ | 打开文件用于读写,如果不存在则创建,如果存在则截断 |
wx+ | 打开文件用于读写,如果存在则打开失败 |
a | 打开文件用于追加,如果不存在则创建 |
ax | 打开文件用于追加,如果路径存在则失败 |
a+ | 打开文件进行读取和追加,如果不存在则创建该文件 |
ax+ | 打开文件进行读取和追加,如果路径存在则失败 |
可以通过属性控制文件的打开状态 |
流式文件写入
同步、异步、简单文件的写入都是一次性的写入,即以一次性就将所有内容从一个文件写入到另一个文件。缺点是都不适合大文件的写入,性能较差,容易导致内存溢出。
流式文件写入就是一次向文件中写入一点,不会造成内存溢出。
创建可写流:fs.createWriteStream(path[, options])
- path:文件路径
- options:配置参数
var fs = require("fs")
var ws = fs.createWriteStream("hello.txt")
// 写内容
ws.write("可写流写入\n")
ws.write("不会被覆盖")
// 关闭流
ws.end()
// 不能用ws.close()
// 监听流的open和close时间来监听流的打开和关闭
// on是绑定长期有限的事件,once是绑定一次性事件
ws.once("open",function (){
console.log("流打开了")
})
ws.on("close",function (){
console.log("流关闭了")
})
hello.txt:
控制台输出:
流打开了
流关闭了
文件的读取
同步文件读取
fs.readSync(fd, buffer[, options])
异步文件读取
fs.read(fd[, options], callback)
简单文件读取
- 同步:
fs.readFileSync(path[, options])
- 异步:
fs.readFile(path[, options], callback)
path要读取的文件的路径
options读取的选项
callback回调函数,通过回调函数将读取到内容返回
回调函数有两个参数:err,data
data是读取到的数据是一个buffer
eg:
var fs = require("fs")
fs.readFile("hello.txt",function (err,data){
if (!err) {
console.log(data.toString())
}
})
输出:
hello
我是hello.txt
流式文件读取
流式文件读取也适用于一些比较大的文件,可以分多次将文件读取到内存中
fs.createReadStream(path[, options])
var fs = require("fs")
var rs = fs.createReadStream("hello.txt")
// 如果要读取一个可读流中的数据,必须要为可读流绑定一个data事件,data事件绑定完毕,它会自动开始读取数据
rs.on("data",function (data){
console.log(data)
})
rs.once("open",function (){
console.log("流打开了")
})
rs.on("close",function (){
console.log("流关闭了")
})
输出:
流打开了
<Buffer 68 65 6c 6c 6f 0a e6 88 91 e6 98 af 68 65 6c 6c 6f 2e 74 78 74>
流关闭了
这里文件比较小所以只读取了一次。
流式文件实现文件的读取和写入
传统写法
var fs = require("fs")
var rs = fs.createReadStream("hello.txt")
var ws = fs.createWriteStream("a.txt")
// 如果要读取一个可读流中的数据,必须要为可读流绑定一个data事件,data事件绑定完毕,它会自动开始读取数据
rs.on("data",function (data){
// console.log(data)
ws.write(data)
})
rs.once("open",function (){
console.log("可读流打开了")
})
rs.on("close",function (){
console.log("可读流关闭了")
// 挂壁
ws.end()
})
ws.once("open",function (){
console.log("可写流打开了")
})
ws.on("close",function (){
console.log("可写流关闭了")
})
输出:
可读流打开了
可写流打开了
可读流关闭了
可写流关闭了
简单写法
可以在可读流和可写流之间建设管道,可以直接将可读流中的内容输出到可写流。
pipe ()
可以将可读流中的内容,直接输出到可写流中
var fs = require("fs")
var rs = fs.createReadStream("hello.txt")
var ws = fs.createWriteStream("a.txt")
rs.pipe(ws)
文件的删除
fs.unlink("./avatar/a.txt",err=> {
console.log(err)
})
fs的其他操作
- 验证路径是否存在:
- fs.exists(path , callback)
- fs.existsSync(path)
var fs = require("fs")
var isExists = fs.existsSync("a.txt")
console.log(isExists)
输出:true
- 获取文件信息:
- fs.stat(path, callback)
- fs.statSync(path)
获取文件的状态
它会给我们返回一个对象,这个对象中保存了当前对象状态的相关信息。
var fs = require("fs")
fs.stat("a.txt",function (err,stat){
console.log(stat)
})
输出:
Stats {
dev: 1190885400,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
blksize: 4096,
ino: 13229323907181608,
size: 21,
blocks: 0,
atimeMs: 1653674170186.6125,
mtimeMs: 1653674152915.8928,
ctimeMs: 1653674152915.8928,
birthtimeMs: 1653674152899.5056,
atime: 2022-05-27T17:56:10.187Z,
mtime: 2022-05-27T17:55:52.916Z,
ctime: 2022-05-27T17:55:52.916Z,
birthtime: 2022-05-27T17:55:52.900Z
}
stat的属性:
- size文件的大小
- isFile()是否是一个文件
- isDirectory()是否是一个文件爽
- 删除文件
- fs.unlink(path, callback)
- fs.unlinkSync(path)
var fs = require("fs")
fs.unlinkSync("a.txt")
- 列出文件
- fs.readdir(path[, options], callback)
- fs.readdirSync(pathl, options])
回调函数中有参数err和files
files是一个字符串数组,每一个元素就是一个文件夹或文件的名字
var fs = require("fs")
fs.readdir(".",function (err,files){
if (!err) {
// files是一个字符串数组,每一个元素就是一个文件夹或文件的名字
console.log(files)
}
})
输出:
[ 'hello.txt', 'node_modules', '文件系统', '简介' ]
- 截断文件
- fs.truncate(path, len, callback)
- fs.truncateSync(path, len)
截断文件:将文件按设置成指定的len大小
var fs = require("fs")
fs.truncateSync("hello.txt",10)
输出:
- 建立目录
- fs.mkdir(path[, mode], callback)
- fs.mkdirSync(path[, mode])
var fs = require("fs")
fs.mkdirSync("a")
就创建了一个a文件夹
- 删除目录
- fs.rmdir(path, callback)
- fs.rmdirSync(path)
var fs = require("fs")
fs.rmdirSync("a")
- 重命名文件和目录
- fs.rename(oldPath, newPath, callback)
- fs.renameSync(oldPath, newPath)
oldPath 旧的路径
newPath新的路径
callback 回调函数
var fs = require("fs")
fs.rename("hello.txt","a.txt",function (err){
if (!err) {
console.log("重命名成功")
}
})
也可以实现文件移动的功能:
var fs = require("fs")
fs.rename("a.txt","C:\\Users\\86198\\Desktop\\a.txt",function (err){
if (!err) {
console.log("移动成功")
}
})
这样文件就移动到桌面上了。
- 监视文件更改写入
- fs.watchFile(filename[, options], listener)
监视文件的修改
filename要监视的文件的名字
options配置选项
listener 回调函数,当文件发生变化时,回调函数会执行
在回调函数中会有两个参数:
curr当前文件的状态
prev修改前文件的状态
——这两个对象都是stats对象
可以通过这两个对象获取到文件的具体变化
var fs = require("fs")
fs.watchFile("hello.txt",function (prev,curr){
console.log("文件发生变化了")
console.log("修改前文件的大小:" + prev.size)
console.log("修改后文件的大小:"+curr.size)
})
输出:
是通过定时机制进行文件的检查,所以有时可能需要等一会才能出现结果。
可以通过修改options的interval属性来设置时间
var fs = require("fs")
fs.watchFile("hello.txt", {interval:1000},function (prev,curr){
console.log("文件发生变化了")
console.log("修改前文件的大小:" + prev.size)
console.log("修改后文件的大小:"+curr.size)
})
这样隔1s就会检查一次
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)