node-初步-二

66次阅读

共计 3680 个字符,预计需要花费 10 分钟才能阅读完成。

文件系统模块

Node 中最常见的内置模块 Filesystem(fs), 该模块提供了处理文件和目录的函数

  • readFile: 读取文件, 并将文件内容传递给函数
  • writeFile: 将文件写到磁盘上
  • readdir: 将目录中的文件以字符串数组的方式返回
  • stat: 用于获取文件信息
  • rename: 用于重命名文件
  • unlink: 用于删除文件
    // 异步版本
   var fs = requier('fs')
   fs.readFile('file.text', 'utf8', function(error, text) {if(error) {throw error}
     console.log('The file contained:', text)
   })
   // 同步版本
   fs.readFileSync('file.text', 'utf8')
   

异步回调函数中通常遵循异步优先, 即第一个参数接收可能错误的对象, 其余参数接收结果
使用同步函数较为节省代码, 再简单的脚本中非常适用, 但是异步函数会带来额外的速度提升, 减少延迟

链接分类

硬链接(Hard Link)

硬链接是指通过索引节点来进行链接。在 Linux 的文件系统中,所有文件都会分配一个索引节点编号 Inode,它是文件在系统中的唯一标识,文件的实际数据放置在数据区域(data block),INode 存储着文件参数信息(元数据 metadata),比如创建时间、修改时间、文件大小、属主、归属的用户组、读写权限、数据所在 block 号等, 多个文件名可以指向同一索引节点 (Inode)。硬链接只能在同一文件系统(盘) 中的文件之间进行链接,不能对目录进行创建。只要文件的索引节点还有一个以上的链接,其中一个链接更改文件内容, 其余链接读取文件内容也发生改变, 只删除其中一个链接并不影响索引节点本身和其他的链接(数据的实体并未删除),只有当最后一个链接被删除后,此时如果有新数据要存储到磁盘上,被删除的文件的数据块及目录的链接才会被释放,空间被新数据暂用覆盖。

软链接(Symbolic Link)

软链接(也叫符号链接),类似于 windows 系统中的快捷方式,与硬链接不同,软链接就是一个普通文件,只是数据块内容有点特殊,文件用户数据块中存放的内容是另一文件的路径名的指向,通过这个方式可以快速定位到软连接所指向的源文件实体。源文件删除, 软链接也会失效, 软链接可以跨文件系统对文件或目录创建。

拓 展

  • 执行 readFile 函数 返回 Promise

    var fs = require('fs')
    function readFilePromise(...args) {return new Promise((resolve, reject) => {fs.readFile(...args, (err, data) => {if (err) {reject(err)
          } else {resolve(data)
          }
        })
      })   
    }
    readFilePromise('a.js').then(data => {}).catch(err => {})
  • 执行 writeFile 函数 返回 Promise

    var fs = require('fs')
    function writeFilePromise(...args) {return new Promise((resolve, reject) => {fs.writeFile(...args, (err) => {if (err) {resolve(err)
          } else {reject()
          }
        })
      })
    }
    writeFilePromise('a.js').then(data => {}).catch(err => {})
  • 将一个基于回调的函数转为一个返回 Promise 的函数

    function promisify(callbackBasedFunction) {return function(...args) {return new Promise((resolve, reject) => {callbackBasedFunction(...args,(err, data) => {if (err) {reject(err)
            } else {resolve(data)
            }
          })
        })
      }
    }
    readFilePromise = promisify(fs.readFile)
    writeFilePromise = promisify(fs.writeFile)
    statunlinkPromise = promisify(fs.stat)
    unlinkPromise = promisify(fs.unlink)
    
  • 将一个基于 Promise 的函数转为一个返回回调的函数

    function callbackify(promiseBased) {return function (...args) {var cb = args.pop()
        promiseBased(...args).then(val => {cb(null, val)
        }, reason => {cb(reason)
        })
      }
    }

当然啦, 这两个函数在标准库中已经集成好了, 就是 utils

var fs = require('fs')
var utils = require('utils')
var readFilePromise = utils.promisify(fs.readFile)
var readFile = utils.callbackify(readFilePromise)

一个一个转还是有点麻烦, 现在的 node 已经提供了 promise 版本的 fs 模块

fs = require('fs').promises
fs.readFile('a.txt').then().catch()

练 习

接收一个文件夹路径,返回这个文件夹里面的所有文件名, 需要递归的得到所有的文件名 并放在一个一维数组里返回
需要写三个版本:

  • 同步版
  • 回调版
  • Promise 版本

  • 同步版
const fs = require('fs')
const fsp = fs.promises

function listAllFilesSync(path) {var stat = fs.statSync(path)
  var result = []
  if (stat.isFile()) {return [path] // 如果路径类型是文件, 直接返回
  } else {var entries = fs.readdirSync(path, { withFileTypes: true}) // 读取所有文件, withFileTypes 生成的数组将填充 fs.Dirent 对象,而不是字符串
    entries.forEach(entry => {
      var fullPath = path + '/' + entry.name // 新的路径为原来的 path 接上新的文件夹名
        var files = listAllFilesSync(fullPath) // 递归, 返回的数组全都 push 到 result 中
        result.push(...files)
    });
    return result
  }
}

console.log(listAllFilesSync('./'))
  • Promise 版本
function listAllFilesPromise(path) {return fsp.stat(path).then(stat => {if (stat.isFile()) {return [path]
    } else {return fsp.readdir(path, {withFileTypes: true}).then(entries => {
        return Promise.all(entries.map(entry => {return listAllFilesPromise(path + '/' + entry.name)
        })).then(arrays => {return [].concat(...arrays)
        })
      })
    }
  })
}

listAllFilesPromise('./').then(console.log)
  • 异步版本
function listAllFilesCallback(path, callback) {fs.stat(path, (err, stat) => {if (stat.isFile()) {callback([path])
    } else {fs.readdir(path, {withFileTypes: true}, (err, entries) => {var result = []
        var count = 0
        entries.forEach((entry, i) => {
          var fullPath = path + '/' + entry.name
          listAllFilesCallback(fullPath, (files) => {result[i] = files
            count++
            if (count == entries.length) {callback([].concat(...result))
            }
          })
        })
      })
    }
  })
}

listAllFilesCallback('./', console.log)

以上的三种方法: 同步版本时间效率不高, promise 版本 return 过多比较繁琐, 异步版本 return 不多 但是嵌套层级不灵活
有没有一种方法可以兼具三者的优点呢?
有! 将生成器函数和 promise 函数组合, 即可优化 promise 异步代码的书写

正文完
 0