《node.js权威指南》(三)在Node.js中操作文件系统

这真的是一篇跨年的文章了,好长,一边看,一边跟着敲代码验证,那么,问题来了,你和谁一起跨年了(机智脸)?

在Node.js中,提供一个fs模块,以实现文件及目录的读写操作。

一、同步方法与异步方法

在Node.js中,使用fs模块来实现所有有关文件及目录的创建,写入及删除操作。在fs模块中,多有文件及目录的操作都可以使用同步或异步这两种方法,即readFile 和readFileSync,有Sync后缀的方法为同步方法,不具有Sync后缀的方法均为异步方法。这两者的区别就是,同步方法立即返回操作结果,在使用同步方法执行的操作结束执行之前,不能执行后续代码,

var fs = require('fs');
var data = fs.readFileSync('./index.html','utf-8');
// 等待操作返回结果,然后利用该结果
console.log('data')

异步方法竟操作结果作为回调函数的参数进行返回,在方法调用之后,可以立即执行后续代码,

var fs = require('fs');
var data = fs.readFile('./index.html', 'utf-8', function(err,data){
    // 操作结果作为回调函数的第二个参数返回
    console.log(data)
});

但是,在异步读取中,如果同时执行两个文件的读取操作,并不确保那个操作结果先被返回,这完全取决于程序读取该文件所花费的时间,如果确保一个文件读取完毕再读取另一个文件,应该在第一个读取文件的回调函数中读取另一个文件。

二、文件的完整读写

异步读取文件

fs.readFile(filename,[options],function(err,data){ })
第一个参数filename:表示要读取文件的路径和名称
第二个参数option:指定使用哪种编码格式来读取该文件,可指定的属性值为‘utf-8’,‘ascii’,‘base64’,
第三个参数callback:表示文件服务完毕后执行的回调函数,回调函数的第一个参数err,为读取文件操作失败时触发的错误对象,第二个参数data,表示读取文件成功后读取到的文件内容。

案例:

var fs = require('fs');
var data = fs.readFile('./index.txt', 'utf-8', function(err,data){
    // 操作结果作为回调函数的第二个参数返回
    if (err) {
        console.log('读取文件发生错误')
    }else {
        console.log(data)
    }
});
案例效果

同步读取文件
fs.readFileSync(filename,[options])
第一个参数filename:表示要读取文件的路径和名称
第二个参数option:指定使用哪种编码格式来读取该文件,可指定的属性值为‘utf-8’,‘ascii’,‘base64’,

案例

var fs = require('fs');
try {
    var data = fs.readFileSync('./index.txt','utf-8');
    // 等待操作返回结果,然后利用该结果
    console.log(data)   
} catch(e) {
    console.log(e);
}
案例效果

异步写入文件
fs.writeFile(path, data, [options], function(err){ });
第一个参数path:用于指定需要被写入文件的完整文件路径及文件名
第二个参数data:用于指定需要写入的内容,参数值可以为一个字符串或一个Buffer对象
第三个参数option:可选参数,为一个对象,在其中指定写入文件时需要使用的选项,不细说。
第四个参数callback:用于读取完毕时执行的回调函数,该回调函数的参数err表示写入文件操作失败时触发的错误对象。

案例

var fs = require('fs');
fs.writeFile('./message.txt','我叫饭饭。\r\ncan you see me now ?',function(err){
    if(err){
        console.log('写文件操作失败。')
    }else {
        console.log('写文件操作成功。')
    }
})

当我运行文件的时候,就会在目录下创建一个message.txt文件,且内容是‘我叫饭饭。
can you see me now ?’

再来一个高级一点的案例,用readFile实现复制图片

var fs = require('fs');
fs.readFile('./a.jpg', 'base64', function(err,data){
    fs.writeFile('./b.jpg',data.toString(),'base64',function(err){
        if(err){
            console.log('写文件操作失败')
        }else {
            console.log('写文件操作成功')
        }
    })
});
复制我爽妹子

那么根据以上的解释,下面几个公式应该很好理解

同步写入文件
fs.writeFileSync(path, data, options);
三个参数与writeFile方法中的参数含义完全相同

异步追加文件
fs.appendFile(path, data, options, callback);
那么我们想在message.txt文件的后面,追加一行文字‘这是追加的数据’。

var fs = require('fs');
fs.appendFile('./message.txt', '这是追加的数据', 'utf-8', function(err){
    if(err){
        console.log('追加文件失败')
    }else {
        console.log('追加文件成功')
    }
});

同步读取文件
fs.appendFileSync(path, data, options);
示例代码

var fs = require('fs');
fs.appendFileSync('./message.txt', '我才是追加的数据');

三、从指定位置处开始读写文件

异步方法打开文件

var fs = require('fs')
fs.open('./message.txt','r', function(err,fd){
   console.log(fd.toString())
})

同步打开文件

var fs = require('fs')
var a = fs.openSync('./message.txt','r');
console.log(a)

同步从文件的指定位置处开始读取文件,一直读取到文件底部,然后将读取到的内容输出到一个缓存区中

fs.read(fd,buffer,offset,length,position,function(err,bytesRead,buffer){})

在read方法中,使用6个参数,其中fd参数必须是open方法(或者openSync方法)所使用的回调函数中返回的文件描述符;buffer参数为一个Buffer对象,用于指定将文件数据读取到哪个缓存区中,offset 、length、position、均为一个整数,其中offset用于指定向缓存区中写入数据时的开始写入位置(以字节为单位),length用于指定从文件中读取的字节数,position用于指定读取文件时的开始位置,callback函数中三个参数,其中err表示读取文件操作失败时所触发的错误对象,bytesRead代表实际读取到的字节数(由于文件的开始读取位置+指定读取的字节数可能大于文件长度,指定读取的字节数可能并不等于实际读取到的字节数);buffer参数为被读取的缓存区对象。

var fs = require('fs')
fs.open('./message.txt','r', function(err,fd){
    var buf = new Buffer(255);
    // 一个汉字的utf编码为三个字节数据
    fs.read(fd,buf,0,9,3,function(err,bytesRead,buffer){
        if (err) {
            console.log("err")
        }else {
            console.log(buffer.slice(0, bytesRead).toString())          
        }
    })  
})

read方法中的position参数用于指定读取文件时的开始位置,如果该参数没null,将从文件的当前被读取位置处(前一次读取时的开始位置+读取字节数)开始读取文件。

同步方式打开文件
var bytesRead = fs.readSync(fd.buffer,offset,length,position)
在readSync方法中,使用5个参数,这5个参数的作用于与指定方法与read方法中的相同。

var fs = require('fs')
fs.open('./message.txt','r', function(err,fd){
    var buf = new Buffer(255);
    // 一个汉字的utf编码为三个字节数据
    var bytesRead = fs.readSync(fd,buf,0,9,3);
    console.log(bytesRead);
    console.log(buf.slice(0, bytesRead).toString());        
})

打开文件之后,可以用fs模块中的write方法或writeSync方法从一个缓存区中读取数据并且从文件的指定处开始写入这些数据。

异步写入文件

fs.write(fd,buffer,offset,length,position,function(err,written,buffer){})
在write方法中,使用6个参数,fd是open(openSync)方法所使用的回调函数中返回的文件描述符,buffer是一个buffer对象,用于指定从哪个缓存中读取数据;offset,length,position均为正数,offset用于指定从缓存区中读取数据的开始读取位置(以字节为单位),length参数用于指定从缓存区中读取的字节数,position用于指定写入文件时的开始位置。callback参数用于指定文件写入完毕时执行的回调函数,回调函数中三个函数,err为写入文件操作失败时所触发的错误对象;written是一个整数值,代表被写入的字节数;buffer是一个buffer对象,代表读取的缓存区对象。

var fs = require('fs')
var buf = new Buffer('我叫饭饭');
fs.open('./message.txt','w', function(err,fd){
    fs.write(fd,buf,3,9,0,function(err,written,buffer){
        if(err){
            console.log('文件写入失败')
        }else{
            console.log('写入文件成功')
        }
    })  
})

那么“是饭饭”三个字就被写入到message中

同步写文件

fs.writeSync(fd,buffer,offset,length,position)

在同步写入文件时,参数和write方法的参数含义相同

在写入文件后,我们经常要关闭文件

异步关闭文件
fs.close(fd,[callback])
在close方法中,使用2个参数,其中fd参数值必须为open(openSync)所使用的回调函数中返回的文件描述符,callback为一个可选参数,用于执行关闭文件操作结束时执行的回调函数,在回调函数中使用一个参数,参数值为关闭该文件操作失败时触发的错误对象。

var fs = require('fs')
var buf = new Buffer('我叫饭饭');
fs.open('./message.txt','w', function(err,fd){
    fs.write(fd,buf,0,9,0,function(err,written,buffer){
        if(err){
            console.log('文件写入失败')
        }else{
            console.log('写入文件成功')
        }
    fs.close(fd,function(err){
        if(err){
            console.log('关闭文件失败')
        }else{
            console.log('关闭文件成功')
        }
    })
    })  
})

同步关闭文件
fs.closeSync(fd)

在使用write(writeSync)方法写入数据时,操作系统的做法是首先将该部分数据读到内存中,再把数据写入到文件中,当数据去玩并不代表数据已经写完,因为可能还有一部分数据在内存缓冲区中,这时,如果调用close(closeSync)方法关闭文件,那么这部分数据就会丢失,这时,我们需要调用fs中的fsync方法对文件进行同步操作,将内存缓冲区中的剩余数据全部写入文件中,方法如下
fs.fsync(fd,[callback])
实例如下

var fs = require('fs')
var buf = new Buffer('我叫饭饭');
fs.open('./message.txt','w', function(err,fd){
    fs.write(fd,buf,0,9,0,function(err,written,buffer){
        if(err){
            console.log('文件写入失败')
        }else{
            console.log('写入文件成功')
        }
    fs.fsync(fd,function(err){
        if(err){
            console.log('失败')
        }else{
            console.log('成功')
        }
    })
    fs.close(fd,function(err){
        if(err){
            console.log('关闭文件失败')
        }else{
            console.log('关闭文件成功')
        }
    })
    })  
})

同步关闭文件
fs.closeSync(fd)

四、创建与读取目录

创建目录
fs.mkdir(path,[mode],function(err){ })
三个参数,path参数表示制动需要被创建的目录的完整路径及目录名,callback喊出用于指定创建目录操作文笔时调用的回调函数,该回调函数中使用一个参数,参数值为创建目录时出发的错误对象。

var fs = require('fs')
fs.mkdir('./Luckfine', function(err){
    if(err){
        console.log('创建目录失败')
    }else{
        console.log('创建目录成功')
    }
});

异步创建目录
fs.mkdirSync(path,[mode])

*同步读取目录
fs.readdir(path,function(err,files){})
一个参数path用于指定需要读取的目录的完整路径及路径名,callback函数用于指定读取目录操作完毕时调用的回调函数,回调函数的第一个参数err,表示读取目录失败时触发的错误对象,第二个参数值为一个数组,其中存放了读取到的文件中的所有文件名的数组。

var fs = require('fs')
fs.readdir('./',function(err,files){
    if(err){
        console.log('读取目录失败')
    }else{
        console.log(files)
    }
})

异步读取文件的方法
var files = fs.readdir(path)

五、查看与修改文件或目录的信息

同步查看文件或目录信息
在fs模块中,可以使用stat或lstat方法查看一个文件或目录信息。这两个方法的唯一区别是查看符号链接文件的信息时,必须使用lstat方法。
fs.stat(path,function(err,stats){ })
fs.lstst(path,function(err,stats){ })
path参数用于指定需要被查看的文件或目录的完整路径及文件名或目录名,回调函数中第一个参数err,表示查看文件或目录信息操作失败时出发的错误对象,stats参数问一个fs.Stats对象。
该对象有如下方法



该对象有如下属性
Stat属性

var fs = require('fs')
fs.stat('./message.txt',function(err,stats){
    console.log(stats)
})
打印Stats结果

异步查看文件或目录信息
var stats = fs.statSync(path)
var stats = fs.lstatSync(path)

六、检查文件或目录是否存在

在fs模块中,可以使用exists方法检查一个文件或目录是否存在
fs.exists(path,function(exists){ })
exists方法中,可以使用两个参数,path用于指定需要被检查的文件或目录的完整路径及目录名,callback函数用于检查文件或目录信息操作完毕时执行的回调函数,参数exists在文件或目录存在的时候,该参数为true,当文件或目录不存在时,该参数为false。

var fs = require('fs')
fs.exists('./message.txt', function(exists){
    if(exists){
        console.log('该文件存在')
    }else{
        console.log('该文件不存在')
    }
});

在使用同步方法检查文件是否存在时,可以使用fs.existSync方法,即
var exists = fs.existsSync(path)
参数path与exists方法的path参数含义一致,文件存在时返回值exists为true,文件不存在时返回false

获取文件或目录的绝对路径

fs.realpath(path,[cache],function( err, resolvedPath ){})

在realpath方法中,可以使用三个参数,其中path为需要查看的文件或目录的完整路径,cache为可选参数,是一个对象,其中存放了一下预先指定的路径。callback函数中为获取文件或目录的绝对路径操作完毕时执行的回调函数,在回调函数中使用两个参数,其中err参数值为获取文件或目录的绝对路径操作失败时出发的错误对象,resolvedPath参数值为获取到的文件或目录的绝对路径。

var fs = require('fs')
fs.realpath('./message.txt', function(err,resolvedPath){
    if(err){throw err}
    console.log(resolvedPath)
});

同步方法获取文件或目录的绝对路径,可以用realpathSync方法,该方法的使用方式
var resolvedPath = fs.realpathSync(path,[cache])

修改文件访问时间及修改时间
在fs模块中,可以使用utimes方法修改文件的访问时间及修改时间,该方法的使用方式如下
fs.utimes(path,atime,mtime,function(err){ })
path用于指定需要被修改时间的文件的完整路径及文件名,atime用于指定修改后的访问时间,mtime用于指定修改后的修改时间,callback函数用于指定修改时间操作完成后执行的回调函数,该回调函数的参数err,表示修改文件时间操作失败时出发的错误对象。

var fs = require('fs')
fs.utimes('./message.txt', new Date(), new Date(), function(err){
    if(err){
        console.log('修改文件时间操作失败')
    }else{
        console.log('修改文件时间操作成功')
    }
});

同步修改文件的访问时间或修改时间时,为
fs.utimesSync(path,atime,mtime)

在用open(openSync)方法打开文件并返回文件描述符后,可以使用fs模块中的futimes方法修改文件的访问时间或修改时间
fs.futimes(fd,actime,mtime,callback)

fs.futimesSync(fd,atime,mtime)

修改文件或目录的读写权限

在fs木块中,可以使用chmod方法修改文件或目录的读写权限
fs.chomd(path,mode,function(err){})
三个参数,path用于指定需要被修改读写权限的文件的完整路径及文件或目录名,mode用于指定修改后的文件或目录读写权限,callback表示修改文件读写权限操作完成后执行的回调函数,该回调函数使用一个参数,参数值为修改文件读写权限操作失败时出发的错误对象。

var fs = require('fs')
// 0600代表所有者可读写,其他人没有任何权限
// 0644代表所有者可读写,其他人只读
// 0755代表所有者有所有权限,其他人可读和执行
// 0740代表所有者有所有权限,所有者所在的组只读
fs.chmod('./message.txt',0600,function(err){
    if(err){
        console.log('修改文件权限操作失败')
    }else{
        console.log('修改文件权限操作成功')
    }
})

同步方式修改文件或目录的读写权限时,可是使用fs模块中的chmodSync
fs.chmodSync(path,mode)
在使用open(openSync)打开文件并返回文件描述后,可以使用fs模块中的fchmod方法修改文件的读写权限
fs.fchmod(fd,mode,callback)
或者
fs.fchmod(fd,mode)

七、可以对文件或目录执行的其他操作

移动文件或目录
fs.rename(oldPath, newPath,function(err){ })

使用三个参数,oldPath参数用于指定被移动文件或目录的完整路径及文件名或目录名;newPath参数用于hiding移动后该晚间或目录的完整路径及文件名或目录名,callback函数用于指定移动操作执行完毕时调用的回调函数,在该回调函数中的参数err,表示移动文件或目录操作失败时触发的错误对象。

var fs = require('fs')
var files = fs.rename('./message.txt','./Luckfine/test.txt',function(err){
    if(err){
        console.log('移动文件操作失败')
    }else{
        console.log('移动文件操作成功')
    }
})

上段代码表示message.txt重命名为test.txt文件,移动到Luckfine文件夹下。

使用同步方式移动文件或目录时
fs.renameSync(oldPath,newPath)

删除空目录

在fs模块中,可以使用rmdir方法删除空目录,该方法使用方式如下
fs.rmdir(path,function(err){})
path参数用于指定需要被删除目录的完整路径及目录名,callback参数用于指定删除空目录操作执行完毕时调用的回调函数,该回调函数使用一个参数,参数值为删除目录操作失败时触发的错误对象。

var fs = require('fs')
fs.rmdir('./Luckfine', function(err){
    if(err){
        console.log('删除空目录操作失败')
    }else{
        console.log('删除空目录成功')
    }
});

同步方法删除空目录时,如下
fs.rmdirSync(path)

监视文件或目录

在fs模块中,可以使用watchFile方法对文件进行监视,并且在监视到文件被修改时执行某些处理
fs.watchFile(filename, [opation], function(curr, prev){})

其中filename用于指定被监视的文件的完整路径及文件名,option参数值可选的,为一个对象,可以在其中使用一个布尔类型的persistent属性值来指定当被监视的文件后是否停止当前正在运行的应用程序,该属性的默认属性值为true,也 可以在options参数中使用一个整数类型的interval属性值来指定每隔多少毫秒监视一次文件是否发生了改变。回调函数用于当被监视的文件发生改变时调用,参数curr是一个fs.Stats对象,代表被修改之后的当前文件,prev参数值也为一个fs.Stats对象,代表被修改之前的当前文件。

var fs = require('fs')
fs.watchFile('./message.txt', function(curr,prev){
    if(Date.parse(prev.ctime) == 0){
        console.log('文件被创建');
    }else if(Date.parse(curr.ctime) == 0){
        console.log('文件被删除')
    }else if(Date.parse(prev.mtime) != Date.parse(curr.mtime)){
        console.log('文件被修改')
    }
});

由于在watchFile方法中第二个参数persistent属性的默认值为true,因此当使用watchFile文件监视文件后,应用城西没有立即退出,如果设置为false,用用程序将立即退出。
如下
fs.watchFile('./message.txt' ,{persistent:false},function(curr, prev){ })
或设置成定时器
fs.watchFile('./message.txt' ,{interval:60*60*1000},function(curr, prev){ })

当使用watchFile对文件进行检测后,可以使用unwatchFile取消当文件发生时所要执行的处理
fs.unwatchFile(filename,function(curr, prev){})
例如

var fs = require('fs')
var fun1 = function(curr,prev){
    if(Date.parse(prev.ctime) == 0){
        console.log('文件被创建');
    }else if(Date.parse(curr.ctime) == 0){
        console.log('文件被删除')
    }else if(Date.parse(prev.mtime) != Date.parse(curr.mtime)){
        console.log('文件被修改')
    }
}
var fun2 = function(curr,prev){
    if(Date.parse(curr.ctime) != 0){
        console.log('文件的尺寸是'+curr.size+'')
    }
}

fs.watchFile('./message.txt', fun1)
fs.watchFile('./message.txt', fun2)
fs.unwatchFile('./message.txt', fun2)

能看下来的都是大神,我都快写不下去了。哇哇


同志们,点赞不花钱~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 文件系统模块是一个封装了标准的 POSIX 文件 I/O 操作的集合。通过require('fs')使用这个模块。...
    保川阅读 745评论 0 0
  • Node.js 常用工具 util 是一个Node.js 核心模块,提供常用函数的集合,用于弥补核心JavaScr...
    FTOLsXD阅读 509评论 0 2
  • //公共引用 varfs =require('fs'), path =require('path'); 1、读取文...
    才気莮孒阅读 813评论 0 1
  • 《战斗小猪+》的主角——一只小猪也向我们展示了它高超的功夫。印象中猪给我们的感觉就是吃饱睡,睡饱吃的形象。这次小猪...
    手游汪阅读 256评论 0 0