Nodejs 作为走向全栈的一把利器,越来越得到前端工程师的追捧,由于Nodejs的非阻塞式IO和异步回调让前端工程师可以无缝隙的从客户端衔接到Node。Node是通过以一个个的package搭建起来的,其中fs作为文件系统模块,让人们可以通过简单的API来实现对文件的增、删、改、减。

注:本文是基于Node 4.x版本讲解,详情查看[官方文档](https://nodejs.org/docs/latest-v4.x/api/fs.html#fs_file_system)

Class: fs.FSWatcher
Event: ‘change’ fs.watch(path, function(event, fileName){})
Event: ‘error’
watcher.close()
Class: fs.ReadStream
Event: ‘open’
Event: ‘close’
readStream.path
Class: fs.Stats
Stat Time Values
Class: fs.WriteStream
Event: ‘open’
Event: ‘close’
writeStream.bytesWritten
writeStream.path
fs.access(path[, mode], callback) 测试对由路由指定文件的权限问题
fs.accessSync(path[, mode]) 同步测试
fs.appendFile(file, data[, options], callback) 添加内容到指定文件中
fs.appendFileSync(file, data[, options]) 同步添加内容到制定文件 返回undefined
fs.chmod(path, mode, callback)
fs.chmodSync(path, mode)
fs.chown(path, uid, gid, callback)
fs.chownSync(path, uid, gid)
fs.close(fd, callback)
fs.closeSync(fd)
fs.createReadStream(path[, options]) 创建一个可读流
fs.createWriteStream(path[, options]) 创建一个可写流

fs.exists(path, callback) // 废弃
fs.existsSync(path) // 废弃

fs.fchmod(fd, mode, callback)
fs.fchmodSync(fd, mode)
fs.fchown(fd, uid, gid, callback)
fs.fchownSync(fd, uid, gid)
fs.fdatasync(fd, callback)
fs.fdatasyncSync(fd)
fs.fstat(fd, callback)
fs.fstatSync(fd)
fs.fsync(fd, callback)
fs.fsyncSync(fd)
fs.ftruncate(fd, len, callback)
fs.ftruncateSync(fd, len)
fs.futimes(fd, atime, mtime, callback)
fs.futimesSync(fd, atime, mtime)
fs.lchmod(path, mode, callback)
fs.lchmodSync(path, mode)
fs.lchown(path, uid, gid, callback)
fs.lchownSync(path, uid, gid)
fs.link(srcpath, dstpath, callback)
fs.linkSync(srcpath, dstpath)
fs.lstat(path, callback)
fs.lstatSync(path)
fs.mkdir(path[, mode], callback) 创建一个文件
fs.mkdirSync(path[, mode]) 同步方式创建文件夹
fs.open(path, flags[, mode], callback) 打开文件
fs.openSync(path, flags[, mode]) 同步打开文件
fs.read(fd, buffer, offset, length, position, callback) 从由fd指定的文件来读取数据
fs.readSync(fd, buffer, offset, length, position)
fs.readdir(path, callback) 读取文件夹中的文件
fs.readdirSync(path) 同步读取文件夹中的文件
fs.readFile(file[, options], callback) 读取文件
fs.readFileSync(file[, options]) 同步读取文件
fs.readlink(path, callback) 读取符号链接的值???
fs.readlinkSync(path)
fs.realpath(path[, cache], callback) 计算绝对路径
fs.realpathSync(path[, cache]) 同步计算绝对路径
fs.rename(oldPath, newPath, callback) 更改文件的位置或文件名
fs.renameSync(oldPath, newPath) 同步更改文件的位置或文件名
fs.rmdir(path, callback) 移除文件夹
fs.rmdirSync(path) 同步阻塞式移除文件
fs.stat(path, callback) 获取文件的状态
fs.statSync(path) 同步获取文件的状态
fs.symlink(target, path[, type], callback) 符号链接
fs.symlinkSync(target, path[, type])
fs.truncate(path, len, callback) 将文件截断到一个指定的长度
fs.truncateSync(path, len)
fs.unlink(path, callback)
fs.unlinkSync(path)
fs.unwatchFile(filename[, listener]) 停止监听文件
fs.utimes(path, atime, mtime, callback)
fs.utimesSync(path, atime, mtime)
fs.watch(filename[, options][, listener])
Caveats
Availability
Inodes
Filename Argument
fs.watchFile(filename[, options], listener) 监测文件
fs.write(fd, buffer, offset, length[, position], callback)
fs.write(fd, data[, position[, encoding]], callback)
fs.writeFile(file, data[, options], callback) 写入文件
fs.writeFileSync(file, data[, options]) 同步写入文件
fs.writeSync(fd, buffer, offset, length[, position])
fs.writeSync(fd, data[, position[, encoding]])

文件系统

Node的文件系统是通过官方实现的fs模块来实现的,通过在代码中使用require('fs')来引入该模块,fs模块所提供的方法都有异步(asynchronous)和同步(synchronous)方法.异步方法总是通过设置一个回调函数callback作为最后一个参数来实现的,传递给回调函数的参数取决于具体的方法,但是通常第一个参数都用来保存方法调用返回的结果,如果方法调用成功则该参数为null或者undefined,反之如果函数调用异常,则该参数通常为程序产生的错误描述对象。同样对,当我们使用同步方法来操作文件的时候,产生的错误会立即抛出,为了防止程序异常我们需要通过try/catch语句来捕获产生的异常。
下面是一个简单的异步调用例子:

1
2
3
4
5
6
7
8
const fs = require('fs');
fs.readFile("filename", 'utf-8', function(err, data){
if(err){
throw err;
}else {
console.log("file read success"!);
}
})

同步调用例子只需要在函数名后面加上Sync

1
2
3
4
5
6
const fs = require('fs');
try{
const data = fs.readFileSync('filename');
}catch(err){
throw err;
}

我们知道,javascript引擎是单线程的,同步方法意味着程序执行时会一直等待该方法执行完全,当某个方法执行所需要的时间很长的时候,程序就会“卡”在这里,尤其是对于后端服务的node来说,无时无刻不在接收客户端发来的请求,当其中某些请求卡住而无法及时返回响应时,对用户来讲是一种极其糟糕的体验,所以一般而言都调用异步方法,这样不会阻塞进程。

fs.readFile(file[,options],callback)

读取文件。
@param file {string} 文件名(可以是文件的相对/绝对url)
@param options {object||string}
encoding {string} 默认值为null
flag {string} 默认 ‘r’
@param callback {function} 回调函数

1
2
3
4
fs.readFile('a/b/filename', (err, data) => {
if (err) throw err;
console.log(data);
});

如果[options]是字符串则它指定的就是encoding 字符串编码,如果没有指定编码类型,则原生的buffer对象将会被返回。

fs.readFileSync(file[,options])

同步读取文件
@param file 文件名
@param options 配置同上面的readFile options
如果指明了编码类型则返回字符串,否者返回buffer对象。

1
2
3
4
5
6
7
const fs = require('fs');
try {
const data = fs.readFileSync("a/b/c.text", "utf-8");
}catch(err){
throw err;
}
console.log(data instanceof Buffer); // false

不指定编码类型:

1
2
3
4
5
6
7
const fs = require('fs');
try {
const data = fs.readFileSync("a/b/c.text");
}catch(err){
throw err;
}
console.log(data instanceof Buffer); // true

fs.writeFile(file,data[,options],callback)

写文件。
@param file {string} 文件名字 可以是绝对/相对路径
@param data {string | buffer} 写入的内容 可以是字符串或者buffer对象
@param options {object | string}
encoding {string} 编码方式 默认为 “stf8”
mode {number} 默认为 0o666
flag {string} 默认为w
@param callback 回调函数

异步写入数据到一个文件中,如果该文件存在则替换掉它, data可以是字符串或者buffer对象
如果data是一个buffer对象encoding配置项将会被忽略,并且它的默认值为utf8
如果options是字符串,那它指代的就是编码方式。

1
fs.writeFile("a.text", "hello fs module", 'uft8', err()=>{throw err})

fs.writeFileSync(file,data[,options])

同步写入文件
@param file {string} 文件名
@param data {string | buffer} 写入文件的内容
@param options {object | string}
encoding {string} 编码方式 默认为 “stf8”
mode {number} 默认为 0o666
flag {string} 默认为w

fs.open(path, flag[,mode],callback)

@param path {string}
@param flag {string}
@param mode {string} default 0666 文件模式(涉及文件的权限粘贴等问题)

下面着重来讲解一下flag可能的值:

  • r 打开一个文件等待被读取,如果文件不存在将会抛出一个异常
  • r+ 打开一个文件用来被读取或写入,如果文件不存在将会抛出一个异常
  • rs 同步方式打开一个文件等待被读取,用来指示操作系统绕过本地的高速缓存
  • rs+ 同步方式打开文件等待被读取或写入,指示操作系统绕过本地高速缓存
  • w 打开一个文件用来写入内容,如果文件不存在的话将会被创建,如果存在的话将会被截断(清除)
  • wx 和w一样,只是当文件存在的时候会失败
  • w+ 打开一个文件用来写入或读取,如果文件不存在将会被创建,存在的话内容将会被清除
  • wx+ 打开一个文件用来写入或读取,只是当文件存在的时候会出错
  • a 打开一个文件等待被添加内容,当文件不存在的时候将会被创建。
  • a+ 打开文件等待读取或添加内容,当文件不存在的时候将会被创建
  • ax 和a一样,只是当文件存在的时候会抛出异常
  • ax+ 和a+一样,只是当文件存在的时候将会抛出异常