敞开生长之旅!这是我参加「日新计划 2 月更文应战」的第 3 天,点击检查活动概况
fs(File system,文件系统) 是 node 的一个内置模块,可用于在多种操作系统中(Windows 、macOS 等)对文件进行操作。查阅 node 的官方文档,能够看到 File system 下有十分多的 API:
它们有的用于对文件进行读写操作,有的用于对文件夹操作等,且都提供同步、异步和 Promise 这 3 种操作办法。下面举几个常用的 API 为例,进行说明。
操作文件
读取文件
同步读取
fs.readFileSync()
用于同步 (Sync) 读取文件,直接传入要读取的文件的途径(留意,假如运用相对途径,相对的是履行 node 指令所在的途径,而不是相对当时文件模块,所以最好运用绝对途径)或文件描述符即可:
// 代码块 1.1.1
const fs = require('fs')
const path = require('path')
// 同步读取
const resSync = fs.readFileSync(path.resolve(__dirname, './test.txt'))
console.log(resSync)
console.log('看看会不会堵塞')
履行成果如下,第 6 行的打印是在第 5 行之后,说明同步操作会堵塞后续代码的运行:
resSync
的成果是 Buffer 目标,本质上是二进制的内容,只是以十六进制来展示。假如想看到文本内容,能够对成果运用 toString()
进行转换:console.log(resSync.toString())
,或许给 fs.readFileSync()
传入第 2 个参数 —— 一个用于指定配置的可选目标,该目标有 2 个特点:
-
encoding
,默许值为null
,也就是成果显现为 buffer,想显现文本能够改为'utf-8'
(或'utf8'
); -
flag
,读取文件时默许值为'r'
,更多 flag 相关信息可检查官方文档。
// 代码块 1.1.2
const resSync = fs.readFileSync('./test.txt', {
encoding: 'utf-8',
flag: 'r'
})
console.log(resSync)
console.log('看看会不会堵塞')
现在看到的 resSync
就为一个字符串了:
异步读取 – Callback
fs.readFile()
用于异步读取文件,其能够传入 3 个参数,前两个与 fs.readFileSync()
相同,第 3 个参数为一个回调函数,当获取到读取成果时被调用:
// 代码块 1.2.1
fs.readFile(
'./test.txt',
{
encoding: 'utf-8'
},
(err, data) => {
if (!err) console.log(data)
}
)
console.log('看看会不会堵塞')
履行成果如下,能够看到异步读取不会堵塞后续代码的履行:
异步读取 – Promise
fs.promises.readFile()
也是用于异步读取文件,但能够避免在采用回调函数的办法获取成果时简单产生的回调阴间:
// 代码块 1.3.1
fs.promises
.readFile('./test.txt', {
encoding: 'utf-8'
})
.then(res => {
console.log(res)
})
.catch(err => console.log(err))
写入文件
写入文件也有同步异步的办法,下面以异步 – callback 的 api fs.writeFile()
为例。
其第 1 个参数能够是文件的地址或文件描述符,假如文件不存在,则会进行创立;
第 2 个参数为要写入的内容;
第 3 个参数为用于指定配置的可选目标,其中有之前介绍过的两个特点 encoding
和 flag
,只不过这儿 encoding
的默许值为 'utf8'
,flag
的默许值为 'w'
,即默许写入的内容会覆盖原有的内容,假如是想在原内容后追加写入,则能够改为 'a'
(append);
第 4 个参数是一个回调函数,在写入操作履行完毕后调用,假如写入发生错误,就会把错误信息作为参数传入:
fs.writeFile(
'./test.txt',
'Hello Juejin',
{
encoding: 'utf8',
flag: 'w'
},
err => {
if (err) {
console.log(err)
return
}
console.log('写入成功')
}
)
文件描述符
前面提到,读取文件的这 3 种办法,传入的第一个参数除了文件的途径外,还能够是文件描述符(file descriptor)。在常见的操作系统中,内核对于每个进程都维护着一张当时翻开的文件和资源的表格,而每个翻开的文件都会被分配一个简单的数字用于标识和盯梢文件,尽管不同的操作系统具体完成可能不同,但 node 帮咱们处理了差异,为每个翻开的文件分配了个数字类型的文件描述符。
咱们能够经过 fs.open()
翻开一个文件来获取文件描述符:
// 代码块 2.1.1
fs.open('./test.txt', (err, fd) => {
if (!err) {
console.log(fd)
}
})
检查类型能够得知其第 2 个参数,也就是回调函数会被传入两个参数,第 1 个为错误信息 err
,第 2 个就是文件描述符 fd
:
得到的成果为 3:
检查文件信息
获取到了文件描述符,咱们能够经过 fs.fstat()
(其第 1 个参数只能是 fd)检查文件信息:
fs.open('./test.txt', (err, fd) => {
if (err) return
fs.fstat(fd, (err, stats) => {
if (err) return
console.log(stats)
fs.close(fd) // 封闭文件
})
})
打印成果如下:
操作文件夹
创立文件夹
fs 模块还能对文件夹进行操作,比方 fs.mkdir()
就能够创立文件夹,mkdir 能够看成是 make directory 的缩写:
fs.mkdir('./test', err => console.log(err)) // 创立 test 文件夹
读取文件夹
fs.readdir()
能够用于读取文件夹,在回调函数中会返回读取到的文件夹中所包含的文件或文件夹,比方 node 目录下的结构如下图所示:
履行如下代码对 node 目录进行读取:
// fs.js
fs.readdir('../node', (err, files) => {
if (!err) console.log(files)
})
打印成果为:[ ‘fs.js’, ‘test’, ‘test.txt’ ]。
假如想获取更具体的信息,能够传入配置目标,将 withFileTypes
设置为 true
:
fs.readdir('../node', { withFileTypes: true }, (err, files) => {
if (!err) console.log(files)
})
那么打印的成果就会经过 Symbol(type)
的值来表明是文件(值为 1
),还是文件夹(值为 2
),关于 Symbol 的介绍可参看 Symbol 详解:
现在还有个问题,就是 test 文件夹里的 index.txt 文件没有被读取到,假如想读取 node 目录下的所有文件,能够经过递归读取:
function readDirRecursive(path) {
fs.readdir(path, { withFileTypes: true }, (err, files) => {
if (err) return
files.forEach(item => {
if (item.isDirectory()) {
readDirRecursive(`${path}/${item.name}`)
} else {
console.log(item.name)
}
})
})
}
readDirRecursive('../node')
咱们也需要将 withFileTypes
设置为 true
,这样返回的 files
数组中的元素才是一个个目标,并且有 name
特点和 isDirectory()
办法能够判断是否为文件夹。
重命名文件夹/文件
fs.rename()
能够重命名文件夹或文件,第 1 个参数为旧称号,第 2 个参数传新称号即可:
fs.rename('./test', './juejin', err => console.log(err))
敞开生长之旅!这是我参加「日新计划 2 月更文应战」的第 3 天,点击检查活动概况