同步方法和异步方法
在Node.js中,使用fs模块来实现所有文件及目录的创建、写入及删除操作。所有对文件及目录的操作都可以使用同步与异步这两种方法。例如,在执行读文件操作时,可以使用readFile方法与readFileSync方法。在这些方法中,所有方法名中具有Sync
后缀的方法均为同步方法,而不具有Sync后缀的方法均为异步方法。这两者的区别是:同步方法立即返回操作结果,在使用同步方法执行的操作结束之前,不能执行后续代码,代码类似如下所示。
1 | var fs = require('fs'); |
而异步方法将操作结果作为回调函数的参数进行返回,在方法调用之后,可以立即执行后续代码,代码类似如下所示。
1 | var fs = require('fs'); |
在大多数情况下,应该调用异步方法。但是在很少的场景中(例如读取配置文件并启动服务器),应该使用同步方法。
如果要确保在一个文件读取完毕后再读取另一个文件,应该使用如下所示的方法。
1 | fs.readFile('./file.html', function (err, data) { |
对文件执行读写操作
完整读写
在完整读取一个文件时,可以使用fs模块中的readFile
方法或readFileSync
方法。
1 | fs.readFile(filename, [options], callback) |
flag的可选值:
可选值 | 作用 |
---|---|
r | 读取文件,如果文件不存在则抛出异常 |
r+ | 读取并写入文件,如果文件不存在则抛出异常 |
rs | 以同步方式读取文件并通知操作系统忽略本地文件系统缓存,如果文件不存在则抛出异常。由于该属性值的使用将使操作系统忽略本地文件系统缓存机制,因此在操作网络文件系统时建议使用该属性值,但由于其对性能产生一定的负面影响,所以在其他场合下不建议使用 |
w | 写入文件。如果文件不存在则创建该文件,如果该文件已存在则清空文件内容 |
wx | 作用与’w’类似,但是以排他方式写入文件 |
w+ | 读取并写入文件。如果文件不存在则创建该文件,如果该文件已存在则清空文件内容 |
wx+ | 作用与’w+’类似,但是以排他方式打开文件 |
a | 追加写入文件,如果文件不存在则创建该文件 |
ax | 作用与’a’类似,但是以排他方式写入文件 |
a+ | 读取并追加写入文件,如果文件不存在则创建该文件 |
ax+ | 作用与’a+’类似,但是以排他方式打开文件 |
在options参数值中,可使用encoding属性指定使用何种编码格式来读取该文件,可指定属性值为“utf8”、“ascii”与“base64”。
callback参数用于文件读取完毕时执行的回调函数。该回调函数的指定方法如下所示。
1 | function (err,data){ |
使用readFile
方法读取文件:
1 | let fs = require('fs'); |
在使用同步方式读取文件时,使用readFileSync
方法,该方法的使用方法如下所示。
1 | let data=fs.readFileSync(filename, [options]) |
在readFileSync
方法中,使用两个参数,这两个参数的含义及指定方法与readFile方法中使用的file参数与options参数的含义及指定方法完全相同。
1 | let fs = require('fs'); |
在完整写入一个文件时,可以使用fs模块中的writeFile方法或writeFileSync方法。先看writeFile
方法,其使用方法如下所示。
1 | fs.writeFile(filename,data,[options],callback) |
mode属性值由4个数字组成,其中第一个数字必须是0,第二个数字用于规定文件或目录所有者的权限,第三个数字用于规定文件或目录所有者所属用户组的权限,第四个数字规定其他人的权限。可以设定的数字如下所示:
1 | 1:执行权限 |
如果需要设置读写等复合权限,可以对以上三个数字进行加运算,例如使用2+4=6来设置读写权限。
使用writeFile方法完整写入文件:
1 | let fs = require('fs'); |
将Buffer对象中数据写入到文件中:
1 | let data = new Buffer('js是最好的语言'); |
设置追加写入:
1 | let fs = require('fs'); |
设置base64编码复制图片:
1 | let fs=require('fs'); |
在使用同步方式写入文件时,使用writeFileSync方法,该方法的使用方法如下所示。
1 | fs.writeFileSync(filename,data,[options]) |
在将一个字符串或一个缓存区中的数据追加到一个文件底部时,可以使用fs模块中的appendFile
方法或appendFileSync
方法。
1 | fs.appendFile(filename,data,[options],callback) |
在appendFile方法中,使用4个参数,其作用及指定方法与writeFile方法所使用的4个参数的作用与指定方法大致相同,区别在于,在options参数值对象中,flag属性的默认属性值为’a’(在文件底部追加写入数据,如果文件不存在,则创建该文件)。
在使用同步方式在文件底部追加数据时,可以使用appendFileSync方法,该方法的使用方式如下所示。
1 | fs.appendFileSync(filename,data,[options]) |
从指定位置处开始读写文件
要实现这一处理,我们首先需要使用fs模块中的open方法或openSync方法打开文件。这里首先介绍open方法。该方法的使用方式如下所示。
1 | fs.open(filename, flags,[mode],callback) |
callback参数用于指定文件打开操作执行完毕时执行的回调函数,其指定方法如下所示。
1 | function (err, fd) { |
该回调函数使用两个参数,其中第一个参数值为打开文件操作失败时所触发的错误对象,第二个参数值为一个整数值,代表打开文件时返回的文件描述符(在Windows操作系统中,文件描述符亦称文件句柄)。
打开文件:
1 | let fs = require('fs') |
在使用同步方式打开文件时,使用openSync方法,该方法的使用方式如下所示。
1 | let fd=fs.openSync(filename, flags,[mode]) |
在打开文件之后,可以在回调函数中使用fs模块中的read方法或readSync方法从文件的指定位置处读取文件,也可以使用fs模块中的write方法或writeSync方法从文件的指定处开始写入数据。
read方法,该方法从文件的指定位置处读取文件,一直读取到文件底部,然后将读取到的内容输出到一个缓存区中。该方法的使用方式如下所示。
1 | fs.read(fd, buffer, offset, length, position, callback) |
callback参数用于指定文件读取操作执行完毕时执行的回调函数,其指定方法如下所示。
1 | function (err,bytesRead,buffer) { |
该回调函数使用三个参数,其中err参数值为读取文件操作失败时所触发的错误对象;bytesRead参数值为一个整数值,代表实际读取的字节数(由于文件的开始读取位置+指定读取的字节数可能大于文件长度,指定读取的字节数可能并不等于实际读取到的字节数);buffer参数值为被读取的缓存区对象。
1 | let fs = require('fs'); |
write方法或writeSync方法从一个缓存区中读取数据并且从文件的指定处开始写入这些数据。
write方法的使用方法如下所示。
1 | fs.write(fd, buffer, offset, length, position, callback) |
callback参数用于指定文件写入操作执行完毕时执行的回调函数。该回调函数的指定方法如下所示。
1 | function (err,written,buffer) { |
该回调函数使用三个参数,其中err参数值为写入文件操作失败时所触发的错误对象;written参数值为一个整数值,代表被写入的字节数;buffer参数值为一个Buffer对象,代表被读取的缓存区对象。
1 | let fs = require('fs'); |
当对文件的读写操作执行完毕后,我们通常需要关闭该文件,尤其是在文件以排他方式被打开的时候。
在fs模块中,提供close方法与closeSync方法以关闭文件。
close方法的使用方法如下所示。
1 | fs.close(fd,[callback]) |
fd参数值必须为open方法所使用的回调函数中返回的文件描述符或openSync方法返回的文件描述符;callback参数为一个可选参数,用于指定关闭文件操作结束时执行的回调函数,在回调函数中使用一个参数,参数值为关闭文件操作失败时触发的错误对象。
创建和读取目录
创建目录
在fs模块中,可以使用mkdir方法创建目录,该方法的使用方式如下所示。
1 | fs.mkdir(path,[mode],callback) |
使用mkdir方法创建目录:
1 | let fs = require('fs'); |
在使用同步方式创建目录时,可以使用fs模块中的mkdirSync方法,该方法的使用方式如下所示。
1 | fs.mkdirSync(path,[mode]) |
读取目录
使用readdir
方法读取目录,该方法的使用方式如下所示。
1 | fs.readdir(path,callback) |
path参数用于指定需要被读取的目录的完整路径及目录名;callback参数用于指定读取目录操作完毕时调用的回调函数,该回调函数的使用方式如下所示。
1 | function (err,files) { |
第一个参数值为读取目录操作失败时触发的错误对象,第二个参数值为一个数组,其中存放了读取到的文件中的所有文件名。
1 | let fs = require('fs'); |
在使用同步方式读取目录时,可以使用readdirSync方法,该方法的使用方式如下所示。
1 | var files=fs.readdirSync(path) |
在readdirSync方法中,使用一个参数,用于指定需要读取的目录的完整路径及目录名,该方法返回由被读取目录中所有文件名构成的数组。
查看与修改文件
查看文件或目录的信息
使用stat
方法或lstat
方法查看一个文件或目录的信息。这两个方法的唯一区别是当查看符号链接文件的信息时,必须使用lstat
方法。这两个方法的使用方式如下所示。
1 | fs.stat(path, callback) |
path参数用于指定需要被查看的文件或目录的完整路径及文件名或目录名,callback参数用于指定查看文件或目录信息操作完毕时执行的回调函数。该回调函数的指定方法如下所示。
1 | function(err,stats) { |
err参数值为查看文件或目录信息操作失败时触发的错误对象,stats参数值为一个fs.Stats对象。该对象拥有如下所示的一些方法,在这些方法中均不使用任何参数。
- isFile方法:用于判断被查看的对象是否为一个文件,如果是的话则返回true,如果不是的话则返回false。
- isDirectory方法:用于判断被查看的对象是否为一个目录,如果是的话则返回true,如果不是的话则返回false。
- isBlockDevice方法:用于判断被查看的文件是否为一个块设备文件,如果是的话则返回true,如果不是的话则返回false,该方法仅在UNIX操作系统下有效。
- isCharacterDevice方法:用于判断被查看的文件是否为一个字符设备文件,如果是的话则返回true,如果不是的话则返回false,该方法仅在UNIX操作系统下有效。
- isSymbolicLink方法:用于判断被查看的文件是否为一个符号链接文件,如果是的话则返回true,如果不是的话则返回false,该方法仅在lstat方法的回调函数中有效。
- isFIFO方法:用于判断被查看的文件是否为一个FIFO文件,如果是的话则返回true,如果不是的话则返回false,该方法仅在UNIX操作系统下有效。
- isSocket:用于判断被查看的文件是否为一个socket文件,如果是的话则返回true,如果不是的话则返回false,该方法仅在UNIX操作系统下有效。
stat对象有如下属性:
- dev:该属性值为文件或目录所在设备ID,该属性值仅在UNIX操作系统下有效。
- ino:该属性值为文件或目录的索引编号,该属性值仅在UNIX操作系统下有效。
- mode:该属性值为使用数值形式代表的文件或目录的权限标志。·nlink:该属性值为文件或目录的硬连接数量。
- uid:该属性值为文件或目录的所有者的用户ID,该属性值仅在UNIX操作系统下有效。
- gid:该属性值为文件或目录的所有者的组ID,该属性值仅在UNIX操作系统下有效。
- rdev:该属性值为字符设备文件或块设备文件所在设备ID,该属性值仅在UNIX操作系统下有效。
- size:该属性值为文件尺寸(即文件中的字节数)。
- atime:该属性值为文件的访问时间。
- mtime:该属性值为文件的修改时间。
- ctime:该属性值为文件的创建时间。
1 | let fs = require('fs'); |
在使用同步方式查看文件信息时,可以使用fs模块中的statSync方法或lstatSync方法,这两个方法的使用方式如下所示。
1 | var stats=fs.statSync(path) |
在使用open方法或openSync方法打开文件并返回文件描述符后,可以使用fs模块中的fstat方法查询被打开的文件信息,该方法的使用方式如下所示。
1 | fs.fstat(fd, callback) |
在使用open方法或openSync方法打开文件并返回文件描述符后,也可以使用同步方式的fstatSync方法查询被打开的文件信息,该方法的使用方式如下所示。
1 | var stats=fs.fstatSync(fd) |
检查文件或目录是否存在
在fs模块中,可以使用exists方法检查一个文件或目录是否存在,该方法的使用方式如下所示。
1 | fs.exists(path, callback) |
在exists方法中,可以使用两个参数,其中path参数用于指定需要被检查的文件或目录的完整路径及文件名或目录名,callback参数用于指定检查文件或目录信息操作完毕时执行的回调函数。
1 | function(exists) { |
1 | let fs=require('fs'); |
在使用同步方法检查文件是否存在时,可以使用fs模块中的existSync方法,该方法的使用方式如下所示。
1 | var exists=fs.existsSync(path) |
获取文件或目录的绝对路径
realpath
方法获取一个文件或目录的绝对路径。该方法的使用方式如下所示。
1 | fs.realpath(path,[cache],callback) |
path参数与callback参数为必须指定的参数,cache参数为可选参数。path参数为需要查看的文件或目录的完整路径;cache参数值为一个对象,其中存放了一些预先指定的路径。例如,在如下所示的代码中,我们使用“/private/etc”
来指定path参数值中“/etc”
字符串所指向的路径。
1 | let cache = {'/etc':'/private/etc'}; |
realpath方法的callback参数用于指定获取文件或目录的绝对路径操作完毕时执行的回调函数,在回调函数中使用两个参数,其中err参数值为获取文件或目录的绝对路径操作失败时触发的错误对象,resolvedPath参数值为获取到的文件或目录的绝对路径。
使用realpath方法获取文件的绝对路径:
1 | let fs=require('fs'); |
在使用同步方式获取文件或目录的绝对路径时,可以使用realpathSync方法,该方法的使用方式如下所示。
1 | let resolvedPath=fs.realpathSync(path,[cache]) |
修改文件访问时间及修改时间
使用utimes方法修改文件的访问时间及修改时间。该方法的使用方式如下所示。
1 | fs.utimes(path,atime,mtime,callback) |
path参数用于指定需要被修改时间的文件的完整路径及文件名;atime
参数用于指定修改后的访问时间;mtime
参数用于指定修改后的修改时间;callback
参数用于指定修改时间操作完成后执行的回调函数,该回调函数使用一个参数,参数值为修改文件时间操作失败时触发的错误对象。
修改文件访问时间:
1 | let fs=require('fs'); |
在使用同步方式修改文件的访问时间或修改时间时,可以使用utimesSync方法,该方法的使用方式如下所示。
1 | fs.utimesSync(path,atime,mtime) |
在使用open方法或openSync方法打开文件并返回文件描述符后,可以使用fs模块中的futimes方法修改文件的访问时间或修改时间,该方法的使用方式如下所示。
1 | fs.futimes(fd,atime,mtime,callback) |
在使用open方法或openSync方法打开文件并返回文件描述符后,也可以使用同步方式的futimesSync方法修改文件的访问时间或修改时间,该方法的使用方式如下所示。
1 | fs.futimesSync(fd,atime,mtime) |
修改文件或目录的读写权限
使用chmod
方法修改文件或目录的读写权限,该方法的使用方式如下所示。
1 | fs.chmod(path, mode, callback) |
path参数用于指定需要被修改读写权限的文件的完整路径及文件或目录名;mode参数用于指定修改后的文件或目录读写权限;callback参数用于指定修改文件读写权限操作完成后执行的回调函数,该回调函数使用一个参数,参数值为修改文件读写权限操作失败时触发的错误对象。
1 | let fs=require('fs'); |
在使用同步方式修改文件或目录的读写权限时,可以使用fs模块中的chmodSync方法,该方法的使用方式如下所示。
1 | fs.chmodSync(path, mode) |
在使用open方法或openSync方法打开文件并返回文件描述符后,可以使用fs模块中的fchmod方法修改文件的读写权限,该方法的使用方式如下所示。
1 | fs.fchmod(fd,mode,callback) |
在使用open方法或openSync方法打开文件并返回文件描述符后,也可以使用同步方式的fchmodSync方法修改文件的访问时间或修改时间,该方法的使用方式如下所示。
1 | fs.fchmodSync(fd,mode) |
其他操作
移动文件或目录
使用rename方法移动文件或目录,当移动后的路径与原路径为同一路径,而移动后的文件名或目录名与原文件名或目录名不同时,则执行文件或目录的重命名操作。
1 | fs.rename(oldPath,newPath,callback) |
oldPath参数用于指定被移动文件或目录的完整路径及文件名或目录名;newPath参数用于指定移动后该文件或目录的完整路径及文件名或目录名;callback参数用于指定移动操作执行完毕时调用的回调函数,在该回调函数中使用一个参数,参数值为移动文件或目录操作失败时触发的错误对象。
1 | let fs=require('fs'); |
在使用同步方式移动文件或目录时,可以使用renameSync方法,该方法的使用方式如下所示。
1 | fs.renameSync(oldPath,newPath) |
创建与删除文件的硬链接
在操作系统中,一个文件被创建之后就拥有了一个文件名,因此该文件的硬链接数量为1。但是我们可以通过某种特殊的操作为该文件再指定一个文件名,而这种特殊的操作称为对该文件创建硬链接。在对该文件创建一个硬链接之后,虽然表面上看起来拥有了两个不同的文件,但是在硬盘中这两个文件只不过是同一个文件的多个硬链接,如果修改一个文件中的内容再打开另一个文件,就会看见另一个文件中的内容也被修改。
在fs模块中,可以使用link方法创建文件的硬链接,该方法的使用方式如下所示。
1 | fs.link(srcpath,dstpath,callback) |
srcpath参数用于指定需要被创建硬链接的文件的完整路径及文件名;dstpath参数用于指定被创建的硬链接的完整路径及文件名,该硬链接与原文件必须位于同一卷中;callback函数用于指定创建硬链接操作完毕时调用的回调函数,在该回调函数中使用一个参数,参数值为创建硬链接操作失败时触发的错误对象。
使用link方法创建文件的硬链接:
1 | let fs=require('fs'); |
在使用同步方式创建文件的硬链接时,可以使用linkSync方法,该方法的使用方式如下所示。
1 | fs.linkSync(srcpath,dstpath) |
unlink方法的使用方式如下所示。
1 | fs.unlink(path,callback) |
使用unlink方法删除硬链接:
1 | let fs=require('fs'); |
创建与查看符号链接
在操作系统中,可以为文件或目录创建一个或多个符号链接。所谓符号链接,是一种特殊的文件,这个文件中仅包含了另一个文件或目录的路径及文件名或目录名。如果打开一个文件的符号链接文件进行编辑,操作系统将自动打开符号链接中所指向的原文件进行编辑,如果打开一个目录的符号链接文件进行文件的创建、编辑或删除操作,则操作系统将自动打开符号链接中所指向的原目录并执行相应的操作。如果删除符号链接文件,不会删除原文件或目录,如果删除或移动原文件或目录,符号链接文件也不会被删除,这时产生一种称为“断链”的现象。
在fs模块中,可以使用symlink方法来创建文件或目录的符号链接,该方法的使用方式如下所示。
1 | fs.symlink(srcpath,dstpath,[type],callback) |
srcpath参数、dstpath参数与callback为必须指定参数,type参数为可选参数。srcpath参数用于指定需要被创建符号链接的文件或目录的完整路径及文件或目录名;dstpath参数用于指定被创建的符号链接的完整路径及文件名;type参数用于指定为文件创建符号链接还是为目录创建符号链接,可指定值为file
(为文件创建符号链接)、dir
(为目录创建符号链接,在非Windows操作系统中只能使用dir参数值)以及junction(为目录创建符号链接,只在Windows操作系统中有效),默认值为file;callback函数用于指定创建符号链接操作完毕时调用的回调函数,在该回调函数中使用一个参数,参数值为创建符号链接操作失败时触发的错误对象。
使用symlink方法创建符号链接:
1 | let fs=require('fs'); |
在使用同步方式创建符号链接时,可以使用fs模块中的symlinkSync方法,该方法的使用方式如下所示。
1 | fs.symlinkSync(srcpath,dstpath,[type]) |
在创建了一个符号链接之后,可以使用fs模块中的readlink方法读取符号链接中所包含的另一个文件或目录的路径及文件名或目录名。该方法的使用方式如下所示。
1 | fs.readlink(path,callback) |
在readlink方法中,可以使用两个参数,其中path参数用于指定符号链接的路径及文件名;callback参数用于指定读取符号链接操作完毕时调用的回调函数,该函数的指定方式如下所示。
1 | function (err,linkString) { |
使用readlink方法读取符号链接:
1 | let fs=require('fs'); |