// 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)
fs.watchFile()
实现原理:轮询。每隔一段时间检查文件是否发生变化。所以在不同平台上表现基本是一致的。
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()
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下可用。
问题来了:
不一致的表现。
不可用的场景。
linux上要recursive咋整。
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。
首先是方法
stats.isFile() -- 是否文件
stats.isDirectory() -- 是否目录
stats.isBlockDevice() -- 什么鬼
stats.isCharacterDevice() -- 什么鬼
stats.isSymbolicLink() (only valid with fs.lstat()) -- 什么鬼
stats.isFIFO() -- 什么鬼
stats.isSocket() -- 是不是socket文件
官网例子: