同步读取html
var fs = require('fs'); var data; try{ data = fs.readFileSync('./fileForRead.txt', 'utf8'); console.log('文件内容: ' + data); }catch(err){ console.error('读取文件出错: ' + err.message); }
输出以下:node
/usr/local/bin/node readFileSync.js 文件内容: hello world
异步读取linux
var fs = require('fs'); fs.readFile('./fileForRead.txt', 'utf8', function(err, data){ if(err){ return console.error('读取文件出错: ' + err.message); } console.log('文件内容: ' + data); });
输出以下git
/usr/local/bin/node readFile.js 文件内容: hello world
适合读取大文件github
var fs = require('fs'); var readStream = fs.createReadStream('./fileForRead.txt', 'utf8'); readStream .on('data', function(chunk) { console.log('读取数据: ' + chunk); }) .on('error', function(err){ console.log('出错: ' + err.message); }) .on('end', function(){ // 没有数据了 console.log('没有数据了'); }) .on('close', function(){ // 已经关闭,不会再有事件抛出 console.log('已经关闭'); });
输出以下shell
/usr/local/bin/node createReadStream.js 读取数据: hello world 没有数据了 已经关闭
备注:如下代码,若是文件不存在,则建立文件;若是文件存在,则覆盖文件内容;数据库
异步写入windows
var fs = require('fs'); fs.writeFile('./fileForWrite.txt', 'hello world', 'utf8', function(err){ if(err) throw err; console.log('文件写入成功'); });
同步写入api
var fs = require('fs'); try{ fs.writeFileSync('./fileForWrite1.txt', 'hello world', 'utf8'); console.log('文件写入成功'); }catch(err){ throw err; }
var fs = require('fs'); var writeStream = fs.createWriteStream('./fileForWrite1.txt', 'utf8'); writeStream .on('close', function(){ // 已经关闭,不会再有事件抛出 console.log('已经关闭'); }); writeStream.write('hello'); writeStream.write('world'); writeStream.end('');
fs.write(fd, buffer, offset, length[, position], callback) fs.write(fd, data[, position[, encoding]], callback) fs.writeSync(fd, buffer, offset, length[, position]) fs.writeSync(fd, data[, position[, encoding]])网络
(err, written, buffer)
。written
表示有xx字节的buffer被写入。备注:fs.write(fd, buffer, offset, length[, position], callback)
跟fs.write(fd, data[, position[, encoding]], callback)
的区别在于:后面的只能把全部的data写入,而前面的能够写入指定的data子串?
fs.exists()
已是deprecated
状态,如今能够经过下面代码判断文件是否存在。
var fs = require('fs'); fs.access('./fileForRead.txt', function(err){ if(err) throw err; console.log('fileForRead.txt存在'); }); fs.access('./fileForRead2.txt', function(err){ if(err) throw err; console.log('fileForRead2.txt存在'); });
fs.access()
除了判断文件是否存在(默认模式),还能够用来判断文件的权限。
备忘:fs.constants.F_OK
等常量没法获取(node v6.1,mac 10.11.4下,fs.constants
是undefined
)
异步版本(若是目录已存在,会报错)
var fs = require('fs'); fs.mkdir('./hello', function(err){ if(err) throw err; console.log('目录建立成功'); });
同步版本
var fs = require('fs'); fs.mkdirSync('./hello');
var fs = require('fs'); fs.unlink('./fileForUnlink.txt', function(err){ if(err) throw err; console.log('文件删除成功'); });
var fs = require('fs'); fs.unlinkSync('./fileForUnlink.txt');
// fs.mkdir(path[, mode], callback) var fs = require('fs'); fs.mkdir('sub', function(err){ if(err) throw err; console.log('建立目录成功'); });
// fs.mkdirSync(path[, mode]) var fs = require('fs'); try{ fs.mkdirSync('hello'); console.log('建立目录成功'); }catch(e){ throw e; }
同步版本,注意:fs.readdirSync()
只会读一层,因此须要判断文件类型是否目录,若是是,则进行递归遍历。
// fs.readdirSync(path[, options]) var fs = require('fs'); var path = require('path'); var getFilesInDir = function(dir){ var results = [ path.resolve(dir) ]; var files = fs.readdirSync(dir, 'utf8'); files.forEach(function(file){ file = path.resolve(dir, file); var stats = fs.statSync(file); if(stats.isFile()){ results.push(file); }else if(stats.isDirectory()){ results = results.concat( getFilesInDir(file) ); } }); return results; }; var files = getFilesInDir('../'); console.log(files);
异步版本:(TODO)
// fs.rename(oldPath, newPath, callback) var fs = require('fs'); fs.rename('./hello', './world', function(err){ if(err) throw err; console.log('重命名成功'); });
fs.renameSync(oldPath, newPath) var fs = require('fs'); fs.renameSync('./world', './hello');
fs.watch()
比fs.watchFile()
高效不少(why)
实现原理:轮询。每隔一段时间检查文件是否发生变化。因此在不一样平台上表现基本是一致的。
var fs = require('fs'); var options = { persistent: true, // 默认就是true interval: 2000 // 多久检查一次 }; // curr, prev 是被监听文件的状态, fs.Stat实例 // 能够经过 fs.unwatch() 移除监听 fs.watchFile('./fileForWatch.txt', options, function(curr, prev){ console.log('修改时间为: ' + curr.mtime); });
修改fileForWatch.txt
,能够看到控制台下打印出日志
/usr/local/bin/node watchFile.js 修改时间为: Sat Jul 16 2016 19:03:57 GMT+0800 (CST) 修改时间为: Sat Jul 16 2016 19:04:05 GMT+0800 (CST)
为啥子?莫非单纯访问文件也会触发回调?
If you want to be notified when the file was modified, not just accessed, you need to compare curr.mtime and prev.mtime.
在 v0.10 以后的改动。若是监听的文件不存在,会怎么处理。以下
Note: when an fs.watchFile operation results in an ENOENT error, it will invoke the listener once, with all the fields zeroed (or, for dates, the Unix Epoch). In Windows, blksize and blocks fields will be undefined, instead of zero. If the file is created later on, the listener will be called again, with the latest stat objects. This is a change in functionality since v0.10.
fs.watch(filename[, options][, listener]) fs.unwatchFile(filename[, listener])
这接口很是不靠谱(当前测试用的v6.1.0),参考 https://github.com/nodejs/node/issues/7420
fs.watch(filename[, options][, listener])#
注意:fs.watch()
这个接口并非在全部的平台行为都一致,而且在某些状况下是不可用的。recursive
这个选项只在mac
、windows
下可用。
问题来了:
The fs.watch API is not 100% consistent across platforms, and is unavailable in some situations. The recursive option is only supported on OS X and Windows.
备忘,不可用的场景。好比网络文件系统等。
For example, watching files or directories can be unreliable, and in some cases impossible, on network file systems (NFS, SMB, etc), or host file systems when using virtualization software such as Vagrant, Docker, etc.
另外,listener回调有两个参数,分别是event
、filename
。其中,filename
仅在linux、windows上会提供,而且不是100%提供,因此,尽可能不要依赖filename
。
在linux、osx上,fs.watch()
监听的是inode。若是文件被删除,并从新建立,那么删除事件会触发。同时,fs.watch()
监听的仍是最初的inode。(API的设计就是这样的)
结论:怎么看都感受这个API很不靠谱,虽然性能比fs.watchFile()要高不少。
先来个例子,在osx下测试了一下,简直使人绝望。。。不管是建立、修改、删除文件,evt
都是rename
。。。
var fs = require('fs'); var options = { persistent: true, recursive: true, encoding: 'utf8' }; fs.watch('../', options, function(event, filename){ console.log('触发事件:' + event); if(filename){ console.log('文件名是: ' + filename); }else{ console.log('文件名是没有提供'); } });
修改下fileForWatch.txt
,看到下面输出。。。感受打死也不想用这个API。。。
贴下环境:osx 10.11.4, node v6.1.0。
触发事件:rename
文件名是: fs/fileForWatch.txt___jb_bak___
触发事件:rename
文件名是: fs/fileForWatch.txt 触发事件:rename 文件名是: fs/fileForWatch.txt___jb_old___ 触发事件:rename 文件名是: .idea/workspace.xml___jb_bak___ 触发事件:rename 文件名是: .idea/workspace.xml 触发事件:rename 文件名是: .idea/workspace.xml___jb_old___
参考linux命令行,不举例子了。。。
fs.chown(path, uid, gid, callback) fs.chownSync(path, uid, gid) fs.fchown(fd, uid, gid, callback) fs.fchownSync(fd, uid, gid)
能够用fs.chmod()
,也能够用fs.fchmod()
。二者的区别在于,前面传的是文件路径,后面传的的文件句柄。
fs.chmod)
、fs.fchmod()
区别:传的是文件路径,仍是文件句柄。fs.chmod()
、fs.lchmod()
区别:若是文件是软链接,那么fs.chmod()
修改的是软链接指向的目标文件;fs.lchmod()
修改的是软链接。fs.chmod(path, mode, callback) fs.chmodSync(path, mode)
fs.fchmod(fd, mode, callback) fs.fchmodSync(fd, mode)
fs.lchmod(path, mode, callback)# fs.lchmodSync(path, mode)
例子:
var fs = require('fs'); fs.chmod('./fileForChown.txt', '777', function(err){ if(err) console.log(err); console.log('权限修改为功'); });
同步版本:
var fs = require('fs'); fs.chmodSync('./fileForChown.txt', '777');
区别:
fs.stat()
vs fs.fstat()
:传文件路径 vs 文件句柄。fs.stat()
vs fs.lstat()
:若是文件是软连接,那么fs.stat()
返回目标文件的状态,fs.lstat()
返回软连接自己的状态。fs.stat(path, callback) fs.statSync(path)
fs.fstat(fd, callback) fs.fstatSync(fd)
fs.lstat(path, callback) fs.lstatSync(path)
主要关注Class: fs.Stats
。
首先是方法
官网例子:
{
dev: 2114, ino: 48064969, mode: 33188, nlink: 1, uid: 85, gid: 100, rdev: 0, size: 527, blksize: 4096, blocks: 8, atime: Mon, 10 Oct 2011 23:24:11 GMT, // 访问时间 mtime: Mon, 10 Oct 2011 23:24:11 GMT, // 文件内容修改时间 ctime: Mon, 10 Oct 2011 23:24:11 GMT, // 文件状态修改时间 birthtime: Mon, 10 Oct 2011 23:24:11 GMT // 建立时间 }
例子:
var fs = require('fs'); var getTimeDesc = function(d){ return [d.getFullYear(), d.getMonth()+1, d.getDate()].join('-') + ' ' + [d.getHours(), d.getMinutes(), d.getSeconds()].join(':'); }; fs.stat('./fileForStat.txt', function(err, stats){ console.log('文件大小: ' + stats.size); console.log('建立时间: ' + getTimeDesc(stats.birthtime)); console.log('访问时间: ' + getTimeDesc(stats.atime)); console.log('修改时间: ' + getTimeDesc(stats.mtime)); });
输出以下:
/usr/local/bin/node stat.js 文件大小: 3613 建立时间: 2016-7-16 12:40:49 访问时间: 2016-7-16 12:40:49 修改时间: 2016-7-16 12:40:49 Process finished with exit code 0
同步的例子:
var fs = require('fs'); var getTimeDesc = function(d){ return [d.getFullYear(), d.getMonth()+1, d.getDate()].join('-') + ' ' + [d.getHours(), d.getMinutes(), d.getSeconds()].join(':'); }; var stats = fs.statSync('./fileForStat.txt'); console.log('文件大小: ' + stats.size); console.log('建立时间: ' + getTimeDesc(stats.birthtime)); console.log('访问时间: ' + getTimeDesc(stats.atime)); console.log('修改时间: ' + getTimeDesc(stats.mtime));
例子:
// fs.access(path[, mode], callback) var fs = require('fs'); fs.access('./fileForAccess.txt', function(err){ if(err) throw err; console.log('能够访问'); });
同步版本:
// fs.accessSync(path[, mode]) var fs = require('fs'); // 若是成功,则返回undefined,若是失败,则抛出错误(什么鬼) try{ fs.accessSync('./fileForAccess.txt'); }catch(e){ throw(e); }
比较底层的接口,实际须要用到的机会很少。须要用到的时候看下文档就行。
r
、r+
、w
、w+
等。可选模式很是多。666
,可读+可写。fs.open(path, flags[, mode], callback) fs.openSync(path, flags[, mode]) fs.close(fd, callback) fs.closeSync(fd)
相对底层的读取接口,参数以下
此外,callback
的回调参数为(err, bytesRead, buffer)
fs.read(fd, buffer, offset, length, position, callback)
fs.appendFile(file, data[, options], callback)
utf8
0o666
a
注意:若是file
是文件句柄,那么
var fs = require('fs'); fs.appendFile('./extra/fileForAppend.txt', 'helo', 'utf8', function(err){ if(err) throw err; console.log('append成功'); });
fs.truncate(path, len, callback) fs.truncateSync(path, len)
fs.ftruncate(fd, len, callback) fs.ftruncateSync(fd, len)
用途参考linux说明文档。
要点:
offset
不会变化。好比经过fs.read()
读取文件内容,就须要特别注意。len
小于文件内容长度,剩余文件内容部分会丢失;若是len
大于文件内容长度,那么超出的部分,会用\0
进行填充。The truncate() and ftruncate() functions cause the regular file named by path or referenced by fd to be truncated to a size of precisely length bytes.
If the file previously was larger than this size, the extra data is lost. If the file previously was shorter, it is extended, and the extended part reads as null bytes ('\0').
The file offset is not changed.
With ftruncate(), the file must be open for writing; with truncate(), the file must be writable.
fs.utimes(path, atime, mtime, callback) fs.utimesSync(path, atime, mtime)
fs.futimes(fd, atime, mtime, callback) fs.futimesSync(fd, atime, mtime)
备注,在命令行下能够
stat
查看文件的状态信息,包括了上面的atime、mtime。touch
修改这几个时间。fs.symlink(target, path[, type], callback) fs.symlinkSync(target, path[, type])
fs.link(srcpath, dstpath, callback) fs.linkSync(srcpath, dstpath)
link() creates a new link (also known as a hard link) to an existing file.
软连接、硬连接区别:参考 或者 [这个]。(http://www.cnblogs.com/itech/archive/2009/04/10/1433052.html)
参考这里。
fs.mkdtemp(prefix, callback) fs.mkdtempSync(prefix)
备忘:跟普通的随便找个目录,建立个随机名字的文件夹,有什么区别?
代码示例以下:
var fs = require('fs'); fs.mkdtemp('/tmp/', function(err, folder){ if(err) throw err; console.log('建立临时目录: ' + folder); });
输出以下:
/usr/local/bin/node mkdtemp.js 建立临时目录: /tmp/Cxw51O
fs.readlink(path[, options], callback) fs.readlinkSync(path[, options])
以下面例子,建立了个软连接指向fileForReadLink.txt
,经过fs.readlink()
就能够找出原始的路径。
var fs = require('fs'); var randomFileName = './extra/fileForReadLink-' + String(Math.random()).slice(2, 6) + '.txt'; fs.symlinkSync('./extra/fileForReadLink.txt', randomFileName); fs.readlink(randomFileName, 'utf8', function(err, linkString){ if(err) throw err; console.log('连接文件内容: ' + linkString); });
相似终端下直接运行readlink
。对于软连接文件,效果同上面代码。对于硬连接,没有输出。
➜ extra git:(master) ✗ readlink fileForReadLink-9827.txt ./extra/fileForReadLink.txt ➜ extra git:(master) ✗ readlink fileForLinkHard.txt ➜ extra git:(master) ✗ readlink fileForLinkSoft.txt ./extra/fileForLink.txt
fs.realpath(path[, options], callback) fs.realpathSync(path[, options])
例子:(不能做用于软连接?)
var fs = require('fs'); var path = require('path'); // fileForRealPath1.txt 是普通文件,正常运行 fs.realpath('./extra/inner/fileForRealPath1.txt', function(err, resolvedPath){ if(err) throw err; console.log('fs.realpath: ' + resolvedPath); }); // fileForRealPath.txt 是软连接, 会报错,提示找不到文件 fs.realpath('./extra/inner/fileForRealPath.txt', function(err, resolvedPath){ if(err) throw err; console.log('fs.realpath: ' + resolvedPath); }); console.log( 'path.resolve: ' + path.resolve('./extra/inner/fileForRealpath.txt') );
输出以下:
path.resolve: /Users/a/Documents/git-code/git-blog/demo/2015.05.21-node-basic/fs/extra/inner/fileForRealpath.txt fs.realpath: /Users/a/Documents/git-code/git-blog/demo/2015.05.21-node-basic/fs/extra/inner/fileForRealPath1.txt /Users/a/Documents/git-code/git-blog/demo/2015.05.21-node-basic/fs/realpath.js:12 if(err) throw err; ^ Error: ENOENT: no such file or directory, realpath './extra/inner/fileForRealPath.txt' at Error (native) Process finished with exit code 1
fs.rmdir(path, callback) fs.rmdirSync(path)
例子以下:
var fs = require('fs'); fs.rmdir('./dirForRemove', function(err){ if(err) throw err; console.log('目录删除成功'); });
fs.fdatasync(fd, callback) fs.fdatasyncSync(fd)
能够参考这里:
一、sync函数 sync函数只是将全部修改过的块缓冲区排入写队列,而后就返回,它并不等待实际写磁盘操做结束。 一般称为update的系统守护进程会周期性地(通常每隔30秒)调用sync函数。这就保证了按期冲洗内核的块缓冲区。命令sync(1)也调用sync函数。 二、fsync函数 fsync函数只对由文件描述符filedes指定的单一文件起做用,而且等待写磁盘操做结束,而后返回。 fsync可用于数据库这样的应用程序,这种应用程序须要确保将修改过的块当即写到磁盘上。 三、fdatasync函数 fdatasync函数相似于fsync,但它只影响文件的数据部分。而除数据外,fsync还会同步更新文件的属性。 对于提供事务支持的数据库,在事务提交时,都要确保事务日志(包含该事务全部的修改操做以及一个提交记录)彻底写到硬盘上,才认定事务提交成功并返回给应用层。
mode
,待确认。