## 文件系统处理 我们在开发命令程序的时候,经常需要对文件做各种操作,比如,创建文件、删除文件、修改文件内容、遍历文件等。虽然`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**