## 文件系統處理
我們在開發命令程序的時候,經常需要對文件做各種操作,比如,創建文件、刪除文件、修改文件內容、遍歷文件等。雖然`NodeJs`內置了`fs`模塊供我們使用,但是其功能相對有限,這里,我將介紹一個第三方擴展模塊[fs-extra](https://www.npmjs.com/package/fs-extra)。
[TOC]
### fs-extra模塊與fs模塊的關系
`fs-extra`模塊是`fs`模塊的擴充。也就是說,使用`fs-extra`模塊可以做到以下兩點:
1.直接調用`fs`模塊所有方法(所以,你可以完全拋棄`fs`模塊)
2.調用`fs-extra`擴充的方法
### fs-extra模塊的安裝
* 全局安裝
~~~
$ npm install fs-extra -g
~~~
* 本地安裝
將當前工作目錄切換為需要使用`fs-extra`模塊的目錄(已經創建了`package.json`文件的目錄)
~~~
$ npm install fs-extra --save
~~~
### 同步操作與異步操作
在介紹具體方法之前,有必要介紹一下文件系統的同步(`Sync`)方法和異步(`Async`)方法。
* 同步方法——只有等被調用方法執行結果返回之后,才會執行方法后面代碼,執行過程是阻塞的。
* 異步方法——方法被調用后無需等待結果返回,直接執行后面代碼,執行結果以回調的方式返回。
`fs-extra`的方法基本上都有一個同步和一個異步的方法,它們的方法定義也非常有規律,**異步方法只需在同步方法的基礎上去掉名字的`Sync`,最后一個參數改為回調方法即可**,下面是一個例子:
~~~
var fse = require('fs-extra');
///異步方法
fse.emptyDir('mydir', function(err){
if (err) return console.error(err)
console.log('success!')
})
//同步方法
fse.emptyDirSync('mydir');
~~~
***為了文章的簡介,下面介紹的常用方法,只介紹同步方法,不介紹異步方法,需要用到的時候,你可以根據規律自行補全。***
### fs-extra常用方法
#### copySync
**將源文件(或目錄)拷貝到目標文件(或目錄)**
* `copySync(src, dest, [options])`
* `src <String>`: 源文件或目錄路徑
* `dest <String>`: 目標文件或目錄路徑
* `options <Object>`: 可選參數,JSON對象
* `overwrite <boolean>`: 覆蓋目標文件或目錄,默認值為true,注意,如果設為false,而目標文件又恰好存在,復制會失敗,但不會拋出異常。
* `errorOnExist <boolean>`: 當overwritef為alse時,設置errorOnExist為true,copy出錯時會拋出異常
* `dereference <boolean>`: 解除符號連接,默認值為false
* `preserveTimestamps <boolean>`: 如果設為true,源文件的最后修改和訪問時間將被重新設置,默認值是false
* `filter <Function>`: 過濾拷貝文件的方法,已廢棄,忽略它
例子:
~~~
var fs = require('fs-extra')
// 文件拷貝
fs.copySync('/tmp/myfile', '/tmp/mynewfile')
// 目錄拷貝,包含子目錄和子文件
fs.copySync('/tmp/mydir', '/tmp/mynewdir')
~~~
#### emptyDirSync
**確保目標目錄是空的,如果目錄不是空的,刪除目錄里所有內容;如果目錄不存在,創建目錄。目錄本身不刪除。**
* `emptyDirSync(dir)`
* `dir <String>`:目標目錄路徑
例子:
~~~
var fs = require('fs-extra')
//確保最終存在一個空的目錄
fs.emptyDirSync('/tmp/some/dir')
~~~
#### ensureFileSync
**確保目標文件存在,如果目標文件父級目錄不存在,則父級目錄也將被創建,如果目標文件存在,不作為。**
* `ensureFileSync(file)`
* `file <String>`:目標文件路徑
例子:
~~~
var fs = require('fs-extra')
var file = '/tmp/this/path/does/not/exist/file.txt'
//創建文件file.txt,如果他的父級目錄/tmp/this/path/does/not/exist/有不存在的,則目錄也創建
fs.ensureFileSync(file)
~~~
#### ensureDirSync
**確保目標目錄存在,如果目標目錄不存在,則創建目標目錄,如果目標目錄存在,不作為。**
例子:
* `ensureDirSync(dir)`
* `dir <String>`:目標目錄路徑
~~~
var fs = require('fs-extra')
var dir = '/tmp/this/path/does/not/exist'
fs.ensureDirSync(dir)
~~~
#### mkdirsSync
**不推薦使用,直接用`ensureDirSync`代替這個方法**
#### moveSync
**將源文件(或目錄)移動(剪切)到目標文件(或目錄)**
* `moveSync(src, dest, [options])`
* `src <String>`: 源文件或目錄路徑
* `dest <String>`: 目標文件或目錄路徑
* `options <Object>`: 可選參數,JSON對象
* `overwrite <boolean>`: 覆蓋已存在的文件或目錄,默認值為false
例子:
~~~
var fs = require('fs-extra')
fs.moveSync('/tmp/somefile', '/tmp/does/not/exist/yet/somefile')
~~~
~~~
var fs = require('fs-extra')
//使用overwrite參數
fs.moveSync('/tmp/somedir', '/tmp/may/already/existed/somedir', { overwrite: true })
~~~
#### outputFileSync
**類似[writeFileSync](),唯一的區別是:當父級目錄不存在時,使用outputFileSync,這些目錄會被逐層創建,而使用writeFileSync時,會報錯**
* `outputFileSync(file, data, [options])`
* `file <String>`: 目標文件路徑
* `data <String> | <Buffer> | <Uint8Array>`: 寫入目標文件的內容
* `options <Object> | <String>`: 和[fs.writeFileSync()](https://nodejs.org/api/fs.html#fs_fs_writefilesync_file_data_options)方法的option參數一樣
例子:
~~~
var fs = require('fs-extra')
var file = '/tmp/this/path/does/not/exist/file.txt'
fs.outputFileSync(file, 'hello!')
var data = fs.readFileSync(file, 'utf8')
console.log(data) // => hello!
~~~
#### outputJsonSync
**類似[writeJsonSync](https://github.com/jprichardson/node-fs-extra/blob/master/docs/writeJson-sync.md),唯一的區別是:當父級目錄不存在時,使用`outputJsonSync`,這些目錄會被逐層創建,而使用`writeJsonSync`時,會報錯**
* `outputJsonSync(file, object, [options])`
* `file <String>`: 目標文件路徑
* `object <Object>`: 寫入目標文件的JSON對象
* `options <Object>`: 和[jsonFile.writeFileSync()](https://github.com/jprichardson/node-jsonfile#writefilesyncfilename-obj-options)方法的option參數一樣
例子:
~~~
var fs = require('fs-extra')
var file = '/tmp/this/path/does/not/exist/file.json'
fs.outputJsonSync(file, {name: 'JP'})
var data = fs.readJsonSync(file)
console.log(data.name) // => JP
~~~
#### readJsonSync
**讀取一個`JSON`文件并解析為一個`JSON`對象**
* `readJsonSync(file,[options])`
* `file <String>`: 源文件路徑
* `options <Object>`: 可選參數,JSON對象
例子:
~~~
var fs = require('fs-extra')
var packageObj = fs.readJsonSync('./package.json')
console.log(packageObj.version) // => 1.0.0
~~~
~~~
var fs = require('fs-extra')
var file = '/tmp/some-invalid.json'
var data = '{not valid JSON'
fs.writeFileSync(file, data)
/*默認情況下,readJsonSync()方法校驗讀取文件的內容,如果文件內容不符合JSON的格式,會拋出異常。如果,將throw參數設為false,則可以阻止異常拋出*/
var obj = fs.readJsonSync(file, { throws: false })
console.log(obj) // => null
~~~
#### removeSync
**刪除目標文件或目錄,即時目錄里面有內容,像命令行使用 `rm -rf `一樣的效果**
* `removeSync(path)`
* `path <String>`:目標文件或目錄路徑
例子:
~~~
var fs = require('fs-extra')
// 刪除文件
fs.removeSync('/tmp/myfile.txt')
//刪除outsider整個目錄
fs.removeSync('/home/outsider')
~~~
#### writeJsonSync
**將一個對象寫入`JSON`文件,推薦使用[outputJsonSync()]()**
* `writeJsonSync(file, object, [options])`
* `file <String>`: 目標文件路徑
* `object <String>`: 寫入目標文件的JSON對象
* `options <Object>`: 和[jsonFile.writeFileSync()](https://github.com/jprichardson/node-jsonfile#writefilesyncfilename-obj-options)方法的option參數一樣
例子:
~~~
var fs = require('fs-extra')
fs.writeJsonSync('./package.json', {name: 'fs-extra'})
~~~
>Tips:
對于命令行程序的開發,上面介紹的方法基本夠用了,遍歷文件的操作會在[增強sell](增強sell.md)介紹,用shelljs實現起來更簡單。
### fs-extra和f's API地址
**`fs-extra`官網:https://www.npmjs.com/package/fs-extra**
**`fs API`:http://nodejs.cn/api/fs.html**