node.js 文件操作
既然到了后台,只要你有权限就可以为所欲为了!
创建文件夹
//fs.js
var
fs = require(
'fs'
);
fs.mkdirSync(
'a'
, 0755);
fs.mkdirSync(
'a/b'
, 0755);
fs.mkdirSync(
'a/b/c'
, 0755);
|
那么它会在fs.js所在目录中创建一个a目录,a目录下再创建b目录,b目录下创建c目录。mkdirSync是一个同步方法,拥有三个参数,第一个是路径,第二个是目录权限,第三个是回调
但这样做有点不妥,如果指定目录已存在,就报错。如果要建立多级目录,一层层判定此目录是否存在,立即会陷入“回调地狱”的境地。虽然node.js对于IO操作的方法都提供了两个版本,一个是同步的,一个是异步的。想了想,搞出我自己的mkdirSync函数,实现比mkdirp的作者好很多。
var
fs = require(
'fs'
);
function
mkdirSync(url,mode,cb){
var
path = require(
"path"
), arr = url.split(
"/"
);
mode = mode || 0755;
cb = cb ||
function
(){};
if
(arr[0]===
"."
){
//处理 ./aaa
arr.shift();
}
if
(arr[0] ==
".."
){
//处理 ../ddd/d
arr.splice(0,2,arr[0]+
"/"
+arr[1])
}
function
inner(cur){
if
(!path.existsSync(cur)){
//不存在就创建一个
fs.mkdirSync(cur, mode)
}
if
(arr.length){
inner(cur +
"/"
+arr.shift());
}
else
{
cb();
}
}
arr.length && inner(arr.shift());
}
//测试代码
mkdirSync(
"aaa/ddd/dd"
,0,
function
(e){
if
(e){
console.log(
'出错了'
);
}
else
{
console.log(
"创建成功"
)
}
});
|
有关目录的创建的讨论,详见这里
创建文件与写入内容
创建文件的方法fs.open(path, flags, [mode], [callback])好像所有语言都很一致,可能是想与最原始的C语言的方法保持一致。这是个异步方法,其同步版本,与其他同步方法一样,就是少了个回调。说一下flags中w与a的不同,w会把已存在的同名文件删除再创建一个,因此要注意。
fs.open(
"test.txt"
,
"w"
);
|
写入内容。这有几种方法,比如fs.write,不过它的第一个参数要求类型为Buffer,而fs.openSync不是返回一个Buffer,因此它不能与fs.write配合使用。
//fs.js
var
fs = require(
'fs'
);
fs.open(
"test.txt"
,
"w"
,0644,
function
(e,fd){
if
(e)
throw
e;
fs.write(fd,
"first fs!"
,0,
'utf8'
,
function
(e){
if
(e)
throw
e;
fs.closeSync(fd);
})
});
|
这时,我们就创建一个文本文件,里面写入"first fs"。不过open中间那两个参数的不是必要的。我们可以再搞一个fs2.js脚本
//fs2.js
var
fs = require(
'fs'
);
fs.open(
"test.txt"
,
"a"
,0644,
function
(e,fd){
if
(e)
throw
e;
fs.write(fd,
"second fs!"
,
function
(e){
if
(e)
throw
e;
fs.closeSync(fd);
})
});
|
执行它,它会在test.txt追加"second fs"这句话。
fs的open, write, close有点像我们在浏览器对document的操作。此外,还有fs.writeFile与fs.writeFileSync,可惜它们不能做追加内容的操作。
var
fs = require(
'fs'
);
fs.writeFile(
"test.txt"
,
"third fs!"
,
function
(e){
//会先清空原先的内容
if
(e)
throw
e;
})
|
删除目录或文件
var
fs = require(
'fs'
);
fs.rmdir(
"aaa"
,
function
(e){
if
(e){
console.log(e)
}
})
/**
{ stack: [Getter/Setter],
arguments: undefined,
type: undefined,
message: 'ENOTEMPTY, Directory not empty \'aaa\'',
errno: 39,
code: 'ENOTEMPTY',
path: 'aaa' }
*/
|
报错,缘由是之前我们还为aaa创建了子目录,必须逐个删除,实在不人性化,于是又造了一个轮子。
var
fs = require(
'fs'
);
var
rmdirSync = (
function
(){
function
iterator(url,dirs){
var
stat = fs.statSync(url);
if
(stat.isDirectory()){
dirs.unshift(url);
//收集目录
inner(url,dirs);
}
else
if
(stat.isFile()){
fs.unlinkSync(url);
//直接删除文件
}
}
function
inner(path,dirs){
var
arr = fs.readdirSync(path);
for
(
var
i = 0, el ; el = arr[i++];){
iterator(path+
"/"
+el,dirs);
}
}
return
function
(dir,cb){
cb = cb ||
function
(){};
var
dirs = [];
try
{
iterator(dir,dirs);
for
(
var
i = 0, el ; el = dirs[i++];){
fs.rmdirSync(el);
//一次性删除所有收集到的目录
}
cb()
}
catch
(e){
//如果文件或目录本来就不存在,fs.statSync会报错,不过我们还是当成没有异常发生
e.code ===
"ENOENT"
? cb() : cb(e);
}
}
})();
rmdirSync(
"aaa"
,
function
(e){
console.log(
"!!!"
+e)
console.log(
"删除aaa目录以及子目录成功"
)
})
|
上面的rmdirSync还可以分解出一个方法,取得给定目录下的所有目录与文件。
var
fs = require(
'fs'
);
var
getAllFolersAndFiles = (
function
(){
function
iterator(url, folders, files){
var
stat = fs.statSync(url);
if
(stat.isDirectory()){
folders.unshift(url);
//收集目录
inner(url,folders, files);
}
else
if
(stat.isFile()){
files.unshift(url);
//收集文件
}
}
function
inner(path,folders,files){
var
arr = fs.readdirSync(path);
for
(
var
i = 0, el ; el = arr[i++];){
iterator(path+
"/"
+el,folders,files);
}
}
return
function
(dir){
var
folders = [], files = [];
try
{
iterator(dir,folders,files);
}
catch
(e){
}finally{
return
{
folders : folders,
files : files
}
}
}
})()
|
如果我们只想取得指定目下的所有文件,还可以更精简些!
function
getAllFiles(root) {
var
result = [], files = fs.readdirSync(root)
files.forEach(
function
(file) {
var
pathname = root+
"/"
+ file
, stat = fs.lstatSync(pathname)
if
(stat === undefined)
return
// 不是文件夹就是文件
if
(!stat.isDirectory()) {
result.push(pathname)
// 递归自身
}
else
{
result = result.concat(getAllFiles(pathname))
}
});
return
result
}
|
监听文件的改动
就是使用watchFile及其同步版本。
var
fs = require(
"fs"
),
sys = require(
"util"
);
fs.open(
"aaa.js"
,
"w"
,0644,
function
(e,fd){
fs.writeSync(fd,
"console.log(1111);"
);
fs.closeSync(fd);
})
fs.watchFile(
"aaa.js"
,
function
(curr, prev) {
sys.puts(
"\n\ttest_file.txt has been edited"
);
sys.puts(
"\tThe current mtime is: "
+ curr.mtime);
sys.puts(
"\tThe previous mtime was: "
+ prev.mtime +
"\n"
);
});
fs.open(
"aaa.js"
,
"a"
,0644,
function
(e,fd){
fs.writeSync(fd,
"console.log(2222)"
);
fs.closeSync(fd);
});
|
此外,node.js还提供了修改了目录文件权限的操作,但这些都是不值一提。自己看看文档就会了。