敞开生长之旅!这是我参加「日新计划 2 月更文应战」的第 3 天,点击检查活动概况

fs(File system,文件系统) 是 node 的一个内置模块,可用于在多种操作系统中(Windows 、macOS 等)对文件进行操作。查阅 node 的官方文档,能够看到 File system 下有十分多的 API:

Node.js 内置模块之 fs

它们有的用于对文件进行读写操作,有的用于对文件夹操作等,且都提供同步异步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 行之后,说明同步操作会堵塞后续代码的运行:

Node.js 内置模块之 fs

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 就为一个字符串了:

Node.js 内置模块之 fs

异步读取 – 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('看看会不会堵塞')

履行成果如下,能够看到异步读取不会堵塞后续代码的履行:

Node.js 内置模块之 fs

异步读取 – 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 个参数为用于指定配置的可选目标,其中有之前介绍过的两个特点 encodingflag,只不过这儿 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

Node.js 内置模块之 fs

得到的成果为 3:

Node.js 内置模块之 fs

检查文件信息

获取到了文件描述符,咱们能够经过 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) // 封闭文件
  })
})

打印成果如下:

Node.js 内置模块之 fs

操作文件夹

创立文件夹

fs 模块还能对文件夹进行操作,比方 fs.mkdir() 就能够创立文件夹,mkdir 能够看成是 make directory 的缩写:

fs.mkdir('./test', err => console.log(err)) // 创立 test 文件夹

读取文件夹

fs.readdir() 能够用于读取文件夹,在回调函数中会返回读取到的文件夹中所包含的文件或文件夹,比方 node 目录下的结构如下图所示:

Node.js 内置模块之 fs

履行如下代码对 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 详解:

Node.js 内置模块之 fs

现在还有个问题,就是 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))

Node.js 内置模块之 fs

敞开生长之旅!这是我参加「日新计划 2 月更文应战」的第 3 天,点击检查活动概况