【快速複習】Node.js中的fs模塊的使用

JavaScript 的是沒有操作文件的能力,但是 Node 是可以做到的,Node 提供了操作文件系統模塊,是 Node 中使用非常重要和高頻的模塊,是絕對要掌握的一個模塊系統。

fs 模塊提供了非常多的接口,這裡主要說一下一些常用的接口。

1.常用API快速複習

fs.stat 檢測是文件還是目錄

const fs = require('fs')  fs.stat('hello.js', (error,stats)=>{      if(error) {          console.log(error)      } else {          console.log(stats)          console.log(`文件:${stats.isFile()}`)          console.log(`目錄:${stats.isDirectory()}`)      }  })

fs.mkdir 創建目錄

onst fs = require('fs')  fs.mkdir('logs', error => {      if(error) {          console.log(error)      } else {          console.log('目錄創建成功!')      }  })

fs.rmdir 刪除目錄

const fs = require('fs')  fs.rmdir('logs', error => {      if(error) {          console.log(error)      } else {          console.log('成功刪除了目錄 logs')      }  })

fs.writeFile 創建寫入文件

const fs = require('fs')  fs.writeFile('logs/hello.log','您好~n', error => {      if(error) {          console.log(error)      } else {          console.log('成功寫入文件');      }  })

fs.appendFile 追加文件

const fs = require('fs')  fs.appendFile('logs/hello.log','hello~n', error => {      if(error) {          console.log(error)      } else {          console.log('成功寫入文件');      }  })

fs.readFile 讀取文件

const fs = require('fs')  fs.readFile('logs/hello.log','utf-8', (error, data) => {      if(error) {          console.log(error)      } else {          console.log(data);      }  })
const fs = require('fs')  fs.unlink(`logs/${file}`, error => {      if(error) {          console.log(error)      } else {          console.log(`成功刪除了文件: ${file}`)      }  })

fs.readdir 讀取目錄

const fs = require('fs')  fs.readdir('logs', (error, files) => {      if(error) {          console.log(error)      } else {          console.log(files);      }  })

fs.rename 重命名,還可以更改文件的存放路徑

const fs = require('fs')  fs.rename('js/hello.log', 'js/greeting.log', error => {      if(error) {          console.log(error)      } else {          console.log('重命名成功')      }  })

2.第三方NPM包 mkdirp 的使用

mkdirp 不僅可以創建文件夾,還可以創建多層的文件夾,類似 mkdir -p 命令

  midir -p tmp/foo/bar/baz  

上述命令也可以在當前目錄創建多層幾文件夾。

如下代碼在當前目錄生成多層級文件夾

const mkdirp = require('mkdirp')  mkdirp('tmp/foo/bar/baz').then(made => console.log(`創建目錄於: ${made}`))  // 創建目錄於: /Users/zhangbing/github/CodeTest/Node/fs/tmp

結果

3.實戰舉例

實戰1

判斷服務器上面有沒有 upload 目錄。如果沒有就創建這個目錄,如果有的話不做操作

const fs = require('fs')  const path = './upload'  fs.stat(path, (err, data) => {      if(err) {          // 執行創建目錄          mkdir(path)          return      }      if(data.isDirectory()) {          console.log('upload目錄存在');      }else{          // 首先刪除文件,再去執行創建目錄          fs.unlink(path, err => {              if(!err) {                  mkdir(path)              }          })      }  })  function mkdir(dir) {      fs.mkdir(dir, err => {          if(err) {              console.log(err);              return          }      })  }

實戰2

wwwroot 文件夾下面有 images css js 以及 index.html, 找出 wwwroot 目錄下面的所有的目錄,然後放在一個數組中

使用同步方法方式

const fs = require('fs')  const path = './wwwroot'  const dirArr = []  const dirs = fs.readdirSync(path)  dirs.forEach(item => {      if(fs.statSync(path + '/' + item).isDirectory()) {          dirArr.push(item)      }  })  console.log('dirArr', dirArr)  // dirArr [ 'css', 'images', 'js' ]

使用 async/await 方式

const fs = require('fs')  const path = './wwwroot'  const dirArr = []  function isDir(path) {      return new Promise((resolve, reject) => {          fs.stat(path, (error, stats) => {              if(error) {                  console.log(error)                  reject(error)                  return              }              if(stats.isDirectory()) {                  resolve(true)              } else {                  resolve(false)              }          })      })  }  function main(){      fs.readdir(path, async (error, data) => {          if(error) {              console.log(error)              return          } else {              for(let i = 0; i < data.length; i++) {                  if(await isDir(path + '/' + data[i])) {                      dirArr.push(data[i])                  }              }              console.log('dirArr', dirArr)          }      })  }  main() // dirArr [ 'css', 'images', 'js' ]

4.管道流

管道提供了一個輸出流到輸入流的機制。通常我們用於從一個流中獲取數據並將數據傳遞到另外一個流中。以下實例我們通過讀取一個文件內容並將內容寫入到另外一個文件中。

const fs = require("fs")  //創建一個可讀流  const readerStream = fs.createReadStream('input.txt')  //創建一個可寫流  const writerStream = fs.createWriteStream('output.txt')  //管道讀寫操作  //讀取input.txt文件內容,並將內容寫入到output.txt文件中  readerStream.pipe(writerStream)  console.log("程序執行完畢")

fs.createReadStream 從文件流中讀取數據

onst fs = require('fs')  const fileReadStream = fs.fileReadStream('demo1.js')  let count = 0  let str = ''  fileReadStream.on('data', chunk => {      console.log(`${++count}接收到:${chunk.length}`)      str += chunk  })  fileReadStream.on('end', () => {      console.log('---結束---')      console.log(count + ',' + star)  })  fileReadStream.on('error', error => {      console.log(error)  })

fs.createWriteStream 寫入文件

const fs = require("fs")  const data ='我是從數據庫獲取的數據,我要保存起來'  //創建一個可以寫入的流,寫入到文件output.txt中  const writerStream = fs.createWriteStream('output.txt')  //使用utf8編碼寫入數據  writerStream.write(data,'UTF8')  //標記文件末尾  writerStream.end()  //處理流事件-->finish事件  writerStream.on('finish', () => {      /*finish-所有數據已被寫入到底層系統時觸發。*/      console.log("寫入完成。")  })  writerStream.on('error', err => {      console.log(err.stack);  })  console.log("程序執行完畢")

實戰:複製圖片

在項目根目錄有一張圖片2020.png,把它複製到 /wwwroot/images

代碼如下

const fs = require("fs")  const readStream = fs.createReadStream('./2020.png')  const writeStream = fs.createWriteStream('./wwwroot/images/2021.png')  readStream.pipe(writeStream)

需要特別注意的是,fs.createWriteStream 要寫入的目錄一定要帶上要複製的文件名,也就是不能寫成 fs.createWriteStream('./wwwroot/images/') 否則在 macOS 下會報如下錯誤:

Error: EISDIR: illegal operation on a directory, open <directory>

本文源碼:https://github.com/dunizb/CodeTest/tree/master/Node/fs