前言
我们在写前端的时候是没有操作文件的需求的,但是在服务端,会有大量的文件操作内容,这个时候我们往往需要对文件进行操作,在服务端编程的领域里面,所有的编程语言都是会有对应的文件操作的API供开发者调用,同样在Node中也有完整的文件系统供开发者使用,今天就让我们首先来学习Node的文件系统,一起开启全栈之路。
一.内容概览

二.判断文件是否存在
😊我们在对文件进行操作的时候一可以首先对文件进行判断,判断这个文件是否存在,在node中提供了一个API来进行文件是否存在的判断fs.exists(filepath,function)
用来传入文件的路径和回调函数来进行文件是否存在的判断。
js
const fs = require('fs')
fs.exists('./aaa.txt', (exists) => {
if (exists) {
console.log("文件存在")
} else {
console.log("文件不存在")
}
})
但是这个API已经被Node官方废弃了,目前更加推荐使用fs.access
和文件访问常量来进行判断,access
这个API非常的强大,传入不同的文件访问常量就可以进行不同的判断,就相当于一个非常的厉害的枪,装不同的子弹,做不同的事情,装穿甲弹可以穿甲,装燃烧弹可以烧伤,access
的基本用法如下,F_OK
是用来判断文件存在性的文件访问常量。
js
const fs = require('fs')
fs.access('./aa.txt', fs.constants.F_OK, (err) => {
if (err) {
console.log("文件不存在")
} else {
console.log("文件存在")
}
})
😈文件访问常量:文件访问常量,用于提供文件系统操作中使用的各种标志、选项和权限。它们的作用是为文件系统相关的操作提供更具可读性和可维护性的代码。这个定义比较模糊,但是大致上就是可以通过不同的文件访问常量来结合access
来进行各种判断,并且一般情况下文件访问常量基本上是和access
进行绑定使用,常见的文件访问常量有如下几种:
🈶文件访问模式(File Access Modes)
fs.constants.F_OK:文件存在性检查。
fs.constants.R_OK:文件读取权限检查。
fs.constants.W_OK:文件写入权限检查。
fs.constants.X_OK:文件执行权限检查。
文件访问常量除了这些还有很多,需要使用的时候可以去官方文档进行查看,或者问下GPT在使用的时候查找一下,基本使用方法基本相同。
三.文件基本读取操作
😊文件的读取:在Node中对文件进行操作一版来讲有三种不同的操作形式分别是,同步文件操作方式,异步回调函数操作方式,Promise操作方式,首先我们先看下这三种方式如何对文件进行读取
js
// 异步方式
fs.readFile(file,encoding,callback)
// 同步方式
fs.readFileSync(file,encoding)
😋异步回调方式读取:
js
const fs = require('fs')
fs.readFile('./index2.js', 'utf-8', (err, data) => {
if (err) {
console.log(err)
} else {
console.log(data)
}
})
😊同步方式读取:
js
const fs = require('fs')
let data = fs.readFileSync('./index2.js', {
encoding: 'utf-8'
})
console.log(data)
🥺Promises的方式读取:我们一般情况下都会使用异步的方式来来进行文件的读取操作,可能比较常用的使用异步回调的这种方式,但是在JS中我们知道,过多的使用回调函数会造成回调地狱的问题,所以在文件操作的时候推荐使用Promise的这种方式进行,这样的话代码比较容易维护。
js
const fs = require('fs')
fs.promises.readFile('./index2.js', {
encoding: 'utf-8'
}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
四.文件基本写入操作
😋文件的写入方式和文件的读取方式是一样的,大致也分为三种方式,同步方式,异步方式,Promise方式
js
// 异步状态
fs.writeFile(file,data,[,options],callback)
// 同步状态
fs.writeFile(file,data,[,options])
file
:文件名或文件描述符。data
:写入文件的内容,可以是字符串也可以是缓冲区。options
:可选参数,encoding
编码方式默认为utf8,mode
,文件模式flag
文件系统标志默认值为w,signal
允许终止正在进行写入操作的文件。
🤡异步回调写入方式:
js
const fs = require('fs')
const data = "hello-World"
fs.writeFile('./test.txt', data, 'utf8', (err) => {
console.log(err)
})
😈同步的文件写入方式
js
const fs = require('fs')
const data = "hello world"
let msg = fs.writeFileSync('./test2.txt', data, {
encoding: 'utf-8'
})
console.log(msg)
🥺使用Promise的方式进行文件的写入操作
js
const fs = require('fs')
const data = "你好"
fs.promises.writeFile('./aaa.txt', data, {
encoding: 'utf-8'
}).then((res) => {
console.log("文件写入成功")
}).catch(_ => {
console.log("文件写入错误")
})
五.文件的打开与文件描述符fd
✅文件描述符fd是什么?其实我们可以简单的理解为系统为文件分配的id
每个文件有自己的id。
- 在常见的操作系统中对应每个进程,内核都维护着一张当前打开着的文件和资源的表格。
- 每个打开的文件都分配了一个称为文件描述符的简单数字标识符。
- 在系统层所有文件的操作系统都使用这些文件描述符来标识和跟踪每个特定的文件。
- Window系统使用了一个虽然不同但是概念上类似的机制来跟踪资源。
🐻打开一个文件:fs.open
用来分配新的文件描述符,一旦被分配,使用文件描述符可以向文件中写入内容,读取文件中的内容,或者请求关于文件的信息。
js
ffs.open('./aaa.txt','r',(err,fd)=>{
if(err){
console.log("文件打开失败",err)
return
}
console.log(fd)
// 可以使用文件描述符进行读取和写入的操作。
fs.writeFile(fd,"aaa",(err,data)=>{
if(err) return
console.log(data) // 输出内容
})
})
🤡读取文件的基本信息
js
fs.open("./foo.txt",'r',(err,fd)=>{
console.log(fd)
fs.fstat(fd,(err,state)=>{
console.log(state)
})
})
六.flag选项相关内容
😋在上面的文件的写入和读取中我们可以看到在文件的写入时候有一个选项是flag,flag选项的作用是指定文件的打开方式和操作类型,我们从上面的内容中可以看到在写入操作的时候有一个option参数,其实这个flag选项就是在option
中进行设置的,常见的flag有以下几种
w
打开文件写入,默认值。w+
打开文件进行读写(可读可写),如果不存在则创建文件。r
打开文件进行读取,读取时候的默认值。r+
打开文件进行读写,不过不存在则抛出异常。a
打开要写入的文件,将流放到文件末尾,如果不存在则创建文件。a+
打开文件进行读写(可读可写),将流放在文件末尾,如果不存在则创建文件。
js
const fs = require('fs')
// 以'w+'方式打开文件,清空文件内容并写入新内容
fs.writeFile('file.txt', 'Hello, World!', { flag: 'w+' }, (err) => {
if (err) {
console.error(err)
} else {
console.log('文件写入成功')
}
})
// 以'r+'方式打开文件,读取文件内容并在指定位置进行追加
fs.writeFile('file.txt', 'This is appended text.', { flag: 'r+' }, (err) => {
if (err) {
console.error(err)
} else {
console.log('文件追加成功')
}
})
七.文件的追加操作
🈶同样的文件除了读写操作还有追加操作,为什么需要追加哪?因为通过上面的代码我们知道如果对一个有数据的文本进行写入操作的话,首先会清空写入的内容之后才会将剩余的内容写入进去,当我们想要进行追加操作我们就需要使用追加的操作或者,使用flag的方式才能够实现,其实Node中提供了追加的API,追加和写入和读取一样,同样提供了,同步操作和异步操作,以及使用Promise的异步操作方式。
js
// 异步回调的代码追加方式
fs.appendFile(path,data,[,options],callback)
// 同步代码追加方式
fs.appendFileSync(path,data,[,options])
😊异步的追加方式
js
const fs = require('fs')
const data = "HelloWorld"
fs.appendFile('./aaa.txt', data, (err, data) => {
if (err) return
console.log(data)
})
😈同步的追加方式
js
const fs = require('fs')
const data = "HelloWorld"
let dataString = fs.appendFileSync('./aaa.txt', data, {
encoding: 'utf-8'
})
console.log(dataString)
🥲使用promise的方式进行追加
js
const fs = require('fs')
const data = "HelloWorld"
fs.promises.appendFile('./file.txt', data, {
encoding: 'utf-8'
}).then(res => {
console.log(res, "文件追加成功")
}).catch(_ => {
console.log(_)
})
八.文件的其他操作
🥺截断文件:在fs模块中可以使用truncate
方法进行文件的截断,删除文件的一部分内容
js
fs.truncate(path,[,len],callback)
path
:用于指定要被截断文件的完整文件路径和文件夹。len
:一个整数数值,用于被指定被截断的文件大小(字节为单位)callback
:用于指定截断文件操作完毕执行的回调函数,该回调函数中使用一个参数。
js
const fs = require('fs')
fs.stat("./aaa.txt", (err, stat) => {
console.log(stat, "打印文件大小")
})
fs.truncate('./aaa.txt', 14, (err) => {
if (err) console.log("操作失败")
else {
fs.stat('./aaa.txt', (err, stats) => {
console.log("截断后的文件大小为", stats.size)
})
}
})
// 截断后的文件大小为 14
👹删除文件:在fs
文件中使用unlink方法对文件进行删除操作,其语法格式如下
js
fs.unlink(path,callback)
js
const fs = require('fs')
fs.unlink('./aaa.txt', (err, data) => {
if (err) return
console.log("文件删除成功")
})
🐻复制文件:Node中复制文件的方式有两种,一种是将文章从一个位置复制到另外一个位置,另外一种是将源文件的内容读出来,然后写入到新文件之中,其实文件写入和读取我们在之前都已经学习过了这次我们主要学习一下使用复制的方式来进行,同时复制操作也和读取和写入操作一样也包含同步和异步。
js
fs.copyFile(src,desc[,mode],callback)
fs.copyFile(src,desc[,mode])
- src:要复制的源文件名
- desc:要复制的目标文件名
- mode:复制操作的修饰符,默认为0
- callback:回调函数
js
const fs = require('fs')
fs.copyFile('./file.txt', './test.txt', (err) => {
if (err) {
console.log("复制文件失败")
} else {
console.log("复制文件成功")
}
})
🤡重命名文件:Node中还提供了直接对文件进行命名的API
js
fs.rename(oldPath,newPath,callback)
- oldPath:源文件名(目录名)
- newPath:新文件名(目录名)
- callback:回调函数、
js
const fs = require('fs')
fs.rename('./file.txt', './new.txt', (err, data) => {
if (err) return
console.log(data, "重命名成功")
})
九.目录相关操作
🐫创建文件夹:在Node中创建文件夹也同时包含同步和异步的方案
js
fs.mkdir(path[,option],callback)
fs.mkdirSync(path[,option])
- path:文件的路径
- option:指定目录的权限
- callback:指定创建文件后调用回调函数。
😋读取目录:
js
fs.readdir(path[,option],callback)
- path:文件名或者文件描述符
- options:可选参数,可以为以下值
- encoding:编码方式
- flag:文件系统标志
- signal:允许正在进行的文件读写操作
- callback:回调函数,在回调函数中有两个参数,具体入下
- err:出现错误的时候错误信息
- data:调用成功时候的返回值
🐻删除空目录:
js
fs.rmdir(path[,option],callback)
- path:用于指定要被删除目录完整路径以及目录名
- options:可选参数
🤡获取目录的绝对路径
js
fs.realpath(path[,option],callback)
- path:路径,可以为字符串或者url
- options:可选参数
- callback:回调函数
十.常见的stat对象相关方法
isFile()
:判断是否是文件isDirectory()
:判断是否是目录isblockDevice()
:判断是否是块设备isCharacterDevice()
:判断是否是字符设备isFIFO()
:判断是否是FIFO设备isSocket()
:是否是socket协议
十一 .总结
😊Node中文件系统提供了非常多的API,但是这些API大致使用方式是相同的,基本包含同步方式,异步方式,Promise方式,我们想把这些API全部记住是不现实的,我们应该大致了解有哪些API然后将常用的记住,其他的内容在使用的时候再进行相关的查询~