nodejs的“文件系统”模块可以操作文件。fs(文件系统)模块是nodejs提供的用于访问本地文件系统的功能模块,使用fs模块可以实现文件及目录的创建,写入、删除等操作。
本教程操作环境:windows7系统、nodejs 12.19.0版、Dell G3电脑。 一、fs模块简介1. 基本概念
fs模块是nodejs的核心模块之一,只要安装了nodejs,就可以直接使用,不需要单独安装。引入fs模块非常简单: let fs = require('fs');接下来就可以调用fs模块的相关接口直接读写文件系统。 fs模块主要提供了以下的接口类:
除了以上的类,fs模块还提供了非常多的实例方法,它们可以直接通过fs调用,如读取文件的方法 let fs = require('fs');
fs.readFile('./README.md', function(err, data) = {
if (err) throw err;
... // 处理数据
})该函数以异步的方式读取文件,以可能抛出的异常作为回调函数的第一个参数(这样设计的目的是“强制”或者“提醒”开发者去处理可能出现的异常),而真正的文档数据则作为第二个参数。 fs模块中几乎所有默认的读写函数都是异步的,不过它也同时提供了这些函数的同步版本,一般是在函数后面加 let fs = require('fs');
try {
let data = fs.readFileSync('./README.md', 'utf8');
} catch(e = {
console.error(e);
})大多数情况下,nodejs推荐使用异步版本的读写函数来提升系统性能。而如果要使用同步版本的函数,应该尽可能使用 2. 文件路径既然是文件系统模块,就必然要根据文件路径找到需要操作的文件。fs模块支持的路径类型分为三类:字符串、Buffer和URL对象。 (1). 字符串字符串类是最常用的路径类型,包括绝对路径和相对路径。绝对路径指的是相对于文件系统根目录的路径,而相对路径是相对于当前工作目录的路径(即运行node命令时所在的目录,可以通过 当使用绝对路径时,windows和其他操作系统存在一定差异。因为在其他大多数操作系统中,驱动器只有唯一的根目录;而在windows上,则存在多个独立的驱动盘(如C盘、D盘等)。从写法上来看,绝对路径一般是以 fs.readFile('/README.md', (err, data) => {
...
});而在windows上,则是以驱动盘开头的: fs.readFile('d://nodejs/README.md', (err, data) => {
...
})我们知道,一般windows都是使用反斜线 fs.readFile('d:\\nodejs\README.md', (err, data) => {
...
})需要注意的是,当使用 而相对路径则是相对于当前工作目录的路径,通常以 // 当前目录的上一级目录下的README.md文件
fs.readFileSync('../README.md');
// 当前目录下nodejs文件夹内的README.md
fs.readFileSync('./nodejs/README.md');
fs.readFileSync('nodejs/README.md');
(2). BufferBuffer类型的路径和字符串几乎没有差别,只是某些操作系统将文件路径视为二进制字节序列,因此通常需要用 (3). URLURL(uniform resource locator,统一资源定位器)是一种通用的资源定位方案,它将任意资源(包括本地文件)都视为网络资源,然后以一种统一的方式定位它们。 fs模块仅支持使用 // 在windows下,定位某个主机上的文件,
// 一般用于读写局域网内的共享文件夹
fs.readFileSync(new URL('file:///主机名/README.md'));
// 定位本地资源
fs.readFileSync(new URL('file:///c:/README.md'));以上两种写法都是针对windows平台的,第一种主要用于局域网内的共享文件读取,第二种用于读写本地文件。 对于其他平台,url的格式如下: fs.readFileSync(new URL('file:///nodejs/README.md'));它会被转化为绝对路径: 二、fs模块的常用类鉴于fs模块的接口数量较为庞大,这里暂不一一探讨,如果感兴趣,请参考 nodejs中文网 - fs模块。本文主要是介绍以下几个接口类中较为常用的一些api,基本上可以满足大部分文件系统操作的需求:
1. fs.Dir(v12.12)这是fs模块对目录(或称为文件夹)的抽象类。调用 比如我们要遍历当前文件夹下的所有子目录及文件,可以用下面的代码(v12.12以上版本可用): async function getChild (path) {
// 读取目录子项,返回一个promise
let dir = await fs.promises.opendir(path);
for await (let dirent of dir) {
console.log(dirent.name);
}}关闭目录有三个方法:
读取该目录的目录项的三个方法为:
async function read (path) {
let dir = await fs.promises.opendir(path);
for await (let dirent of dir.read()){
...
}}
2. fs.Dirent(v10.10)目录项类。当通过
另外, 3. fs.ReadStream读取流类,用于流式读取文件。该类由
回调函数接收文件描述符
4. fs.Stats提供对文件信息的描述。调用 一个 Stats {
dev: 2114, // 设备的数字标识符
ino: 48064969, // 设备的索引号
mode: 33188, // 文件类型和模式
nlink: 1, // 文件的硬链接数
uid: 85, // 该文件拥有者的标识符
gid: 100, // 拥有该文件的群组的标识符
rdev: 0, // 数字型设备表标识符
size: 527, // 文件大小,单位为字节
blksize: 4096, // 文件系统块的大小
blocks: 8, // 文件系统为当前文件分配的块数
atimeMs: 1318289051000.1, // 上次被访问时间
mtimeMs: 1318289051000.1, // 上次被修改的时间
ctimeMs: 1318289051000.1, // 上次更改文件状态的时间
birthtimeMs: 1318289051000.1, // 文件的创建时间
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
}每个 同时,它还有与 5. fs.WriteStream写入流类,用于流式地写入数据。它由 与 每个 三、fs模块的常用方法fs模块提供了很多读写文件系统资源的函数,上一部分介绍的类主要是对这些函数操作结果的封装。下面来介绍一些常用的方法: 1. fs.access(path [,mode], callback)检查文件的可用性。 第一个参数path为文件路径,可以是字符串、Buffer或URL类型; 比如我们需要检查当前文件夹下是否存在 fs.access('package.json', fs.constants.F_OK, (err) => {
if (err) {
... // 文件存在
} else {
... // 文件不存在
}})一般来说,不应该在检查文件可用性之后立即读写文件,因为从检查文件可用性到实际读写文件的过程中,该文件的状态可能发生变化(比如其他进程操作了该文件),这会导致文件可用性检查失效。因此 该方法还有一个同步版本: try {
fs.accessSync('package.json', fs.constants.R_OK | fs.constants.W_OK);
console.log('可以读写');
} catch (err) {
console.error('无权访问');
}2. fs.appendFile(path, data[, options], callback)向文件中追加数据。
fs.appendFile('README.md', '这是要添加的数据', (err) => {
if (err) {
console.log('数据追加失败');
} else {
console.log('数据追加成功');
}})该方法的同步版本为 3. fs.chmod(path, mode, callback)修改文件的权限。 文件系统中每个文件都有读、写和执行三个权限,用r、w和x表示。其中r的权重为4,w的权重为2,x的权重为1,即当用户拥有读权限时,权限值加4,拥有写权限时权限值加2,拥有执行权限时权限值加1。
这种权重分配使得任何一种权限拥有情况的权限值都是不同的,因此只需要一个八进制数字就可以表示某个用户对某个文件拥有哪些权限。 比如某个用户拥有对某个文件的读写权限,而没有执行权限,则他的权限值为 对一个文件而言,系统中存在三类用户:文件的拥有者、拥有该文件的用户组和其他用户。文件系统使用三个八进制数字,来表示这三类用户对某个文件的权限。比如当某个文件的权限值为
该方法的同步版本为 4. fs.chown(path, uid, gid, callback)修改文件的拥有者。 第一个参数为文件路径;第二个参数为新的文件拥有者的用户标识符;第三个参数为该文件所属的用户组的标识符,最后一个参数为执行完毕后的回调函数。 uid和gid都是number类型,是文件系统为每个用户和用户组分配的唯一id,callback则会在操作失败时得到一个错误对象。 该方法的同步版本为 5. fs.close(fd, callback)异步地关闭一个文件。 第一个参数 fs.open('README.md', 'a', (err, fd) => {
...
fs.close(fd, (err) => {
if (err) {} // 关闭失败
});
})该方法的异步版本为 6. fs.constantsfs模块提供的常量,参见fs常量。 7. fs.copyFile(src, dest[, mode], callback)拷贝一个文件。 第一个参数
第四个参数为为执行之后回调函数,与其他异步函数一致,它也会在失败时接收到一个异常对象。 它的同步版本为 8. fs.createReadStream(path[, options])创建一个读取流。常见用法为: let fs = require('fs');
let rs = fs.createReadStream('./1.txt',{
highWaterMark:3, //文件一次读多少字节,默认 64*1024
flags:'r', //默认 'r'
autoClose:true, //默认读取完毕后自动关闭
start:0, //读取文件开始位置
end:3, //流是闭合区间 包含start也含end
encoding:'utf8' //默认null
});
rs.on("open",()=>{
console.log("文件打开")
});
// 自动触发data事件 直到读取完毕
rs.on('data',(data)=>{
console.log(data);
});9. fs.createWriteStream(path[, options])创建一个写入流。常见用法为: const fs=require('fs');
const path=require('path');
let writeStream=fs.createWriteStream('./test/b.js',{encoding:'utf8'});
//读取文件发生错误事件
writeStream.on('error', (err) => {
console.log('发生异常:', err);
});
//已打开要写入的文件事件
writeStream.on('open', (fd) => {
console.log('文件已打开:', fd);
});
//文件写入完成事件
writeStream.on('finish', () => {
console.log('写入已完成..');
console.log('读取文件内容:', fs.readFileSync('./test/b.js', 'utf8')); //打印写入的内容
console.log(writeStream);
});
//文件关闭事件
writeStream.on('close', () => {
console.log('文件已关闭!');
});
writeStream.write('这是我要做的测试内容');
writeStream.end();10. 基于文件描述符的一组函数如 11. fs.mkdir(path[, options], callback)创建一个目录(即文件夹)。 第一个参数path为要创建文件夹的路径;
第三个参数为执行完毕的回调函数,它的第一个参数为可能的异常对象,当 而当要创建的目录已经存在时,如果 创建目录的用法如下: fs.mkdir('nodejs/lib', {recursive: true}, (err, path) => {
...})该代码试图在当前路径下的nodejs文件夹内创建lib文件夹,并且要递归地创建父目录。即假如当前目录下没有nodejs文件夹,则先创建它。创建完成后,如果nodejs文件夹是新创建的,则path就是它的路径;如果nodejs已经存在了,则path是新创建的lib文件夹的路径。 该方法的同步版本为 12. fs.open(path[, flags[, mode]], callback)打开一个文件。 第一个参数为要打开的文件的路径; fs.open('README.md', 'r', (err, fd) => {
...
fs.close(fd, (err) => {})})它的同步版本为 13. fs.opendir(path[, options], callback)打开一个目录。 第一个参数为目录的路径;
第三个参数为callback,即打开目录后的回调函数。该回调函数可接受两个值,一个是可能的异常对象,另一个是打开的目录对象,类型为 它的同步版本为 14. fs.readFile(path[, options], callback)异步地读取文件数据。 该方法会默认先用 path除了可以是文件路径外,还可以是文件描述符。如果传入的是文件描述符,则默认在读取完毕后不会关闭文件,并且后续的读取会接着上次读取的位置继续向后。 options支持以下两个参数:
如果只需要指定编码格式,options还可以是一个字符串,如 回调函数的第一个参数为可能的异常对象,第二个参数则是从文件中读出的数据,可能的数据类型为字符串或Buffer。如 fs.readFile('README.md', 'utf8', (err, data) => {
if (err) { console.log('读取失败'); }
else {
console.log(data);
}})该方法的同步版本为 另外该方法还有一个可替代方法, 15. fs.rename(oldPath, newPath, callback)将oldPath指定的文件重命名为newPath指定的文件,如果该文件已存在,则覆盖它。 回调函数只接收可能抛出的异常对象。 它的同步版本为 16. fs.stat(path[, options], callback)获取某个文件的详细信息。 如 fs.stat('README.md', {bigint: true}, function(err, stats) {
console.log(stats.isDirectory());
console.log(stats);
});options仅支持bigint这一个参数,表示返回的stats对象是 它的同步版本为 17. fs.writeFile(file, data[, options], callback)类似于 file参数为要写入的文件路径,或文件描述符。 回调函数仅支持一个参数,即可能抛出的异常对象。 该方法的同步版本为 当使用 总结以上所列举的只是fs模块中较为常用的一些api,官方文档中还有很多其他用途的接口,感兴趣的请参考nodejs中文网 - fs模块。 如果需要在async函数中使用上述api,可以调用fs模块提供的promise封装版本,如: let fsPromises = require('fs').promises;
// 或let fsPromises = require('fs/promises');
// 或let fs = require('fs'); let fsPromises = fs.promises;
fsPromise.readFile().then((err, data) => {
...
})
async function print (path) {
try {
let data = await fsPromise.readFile(path, 'utf8');
console.log(data); // 读取成功,输出data
} catch (e => {
... // 读取失败
})
}【推荐学习:《nodejs 教程》】 以上就是nodejs的哪个模块可以操作文件的详细内容,更多请关注模板之家(www.mb5.com.cn)其它相关文章! |
