【Node.js】 fs模块全解析

在这里插入图片描述


🔥【Node.js】 fs模块全解析

📢 引言

在Node.js开发中,fs模块犹如一把万能钥匙,解锁着整个文件系统的操作。从读取文件、写入文件、检查状态到目录管理,无所不能。接下来,我们将逐一揭开fs模块中最常用的那些方法神秘面纱,搭配生动的代码示例,让学习过程变得有趣而高效!🌟


📚 Ⅰ. 同步与异步读取文件

💡 fs.readFileSync() & fs.readFile()

  • fs.readFileSync(path, options) ——同步读取文件。接受两个参数:文件路径回调函数。同步读取文件时,Node.js会阻塞当前执行线程,直到文件读取完毕并将内容返回给调用者。这意味着在文件读取完成之前,程序的其他部分无法继续执行
  • fs.readFile(path, options, callback) ——异步读取文件。接受三个参数:文件路径编码格式回调函数。异步读取文件时,Node.js并不会阻塞主线程,而是将读取操作交由操作系统在后台执行。当文件读取完成后,Node.js会通过回调函数通知用户程序结果
const fs = require('fs');
// 同步读取文件
try {
	const data = fs.readFileSync('./test-read-sync.txt', 'utf8');
	console.log('同步读取文件-File content:', data);
} catch (err) {
	console.error('同步读取文件出错-Error reading file:', err);
}


// 异步读取文件
fs.readFile('./test-read-async.txt', 'utf8', (err, data) => {
	if (err) {
		console.error('异步读取文件出错-Error reading file:', err);
	} else {
		console.log('异步读取文件-File content:', data);
	}
});

虽然同步读取在逻辑上更简单直观,但它的缺点是如果文件很大或者I/O速度较慢,整个程序可能会暂时挂起,影响整体性能。在大部分场景下,尤其是在强调高性能和高并发的应用中,应当优先考虑使用异步I/O。

异步过程中,Node.js可以继续执行其他任务,提高了程序的并发性能。因此,异步读取通常用于避免I/O操作导致的阻塞,特别是在服务器端处理网络请求时,这能够确保多个请求可以并行处理而不受单一文件读取操作的限制。


📃 Ⅱ. 同步与异步写入文件

💡 fs.writeFileSync() & fs.writeFile()

  • fs.writeFileSync(path, data[, options]) ——同步写入文件。接收三个参数:文件路径(必需)、要写入的数据(必需)以及可选的选项对象(如指定字符编码)。如同步读取文件一样,同步写入文件也会阻塞当前执行线程,直到文件完全写入完成。
  • fs.writeFile(path, data[, options], callback) ——异步写入文件。接收三个主要参数:文件路径(必需)、要写入的数据(必需)、可选的选项对象以及一个回调函数。异步写入文件不会阻塞主线程,而是将写入操作安排到事件循环队列中,一旦写入完成,便调用回调函数通知结果。
const fs = require("fs")
// 同步写入文件
try {
	fs.writeFileSync('./test-write-sync.txt', '---这里是被写入的内容---');
	console.log('同步写入文件-File written successfully');
} catch (err) {
	console.error('同步写入文件出错-Error writing file:', err);
}
// 异步写入文件
fs.writeFile('./test-write-async.txt', '---这里是被写入的内容---', (err) => {
	if (err) {
		console.error('异步写入文件出错-Error writing file:', err);
	} else {
		console.log('异步写入文件-File written successfully');
	}
})

🖋 Ⅲ. 同步与异步追加写入文件

💡 fs.appendFileSync() & fs.appendFile()

  • fs.appendFileSync(path, data[, options])——同步追加写入文件。接受两个参数:文件路径要写入的数据
  • fs.appendFile(path, data[, options], callback)——异步追加写入文件。接受三个参数:文件路径要写入的数据以及回调函数
// 导入fs模块,来操作文件
const fs = require("fs")

// 同步追加写入文件
try {
	fs.appendFileSync('./test-append-sync.txt', '---这里是被追加的内容---');
	console.log('同步追加写入文件-File written successfully');
} catch (err) {
	console.error('同步追加写入文件出错-Error writing file:', err);
}

// 异步追加写入文件
fs.appendFile('./test-append-async.txt', '---这里是被追加的内容---', (err) => {
	if (err) {
		console.error('异步追加写入文件出错-Error writing file:', err);
	} else {
		console.log('异步追加写入文件-File written successfully');
	}
})


🚀 Ⅳ. 文件状态检查

💡 fs.stat() & fs.statSync()

  • fs.stat(path, callback) ——异步获取文件状态信息。此方法接收两个参数:文件路径(必需)以及一个回调函数。回调函数接收两个参数:错误对象(如果有错误发生)和一个fs.Stats对象,该对象包含了文件或目录的各种状态信息。
  • fs.statSync(path) ——同步获取文件状态信息。此方法仅接收一个参数:文件路径(必需),并直接返回一个fs.Stats对象,如果不成功,则抛出错误。
const fs = require('fs');

// 异步检查文件状态示例
fs.stat('./test-file.txt', (err, stats) => {
  if (err) {
    console.error('获取文件状态失败:', err);
  } else {
    console.log(`文件类型:${stats.isFile() ? '文件' : stats.isDirectory() ? '目录' : '其他'}`);
    console.log('文件大小(字节):', stats.size);
    console.log('最后一次修改时间:', stats.mtime.toLocaleString());
  }
});
// 同步检查文件状态示例
try {
  const stats = fs.statSync('./test-file.txt');
  console.log(`文件类型:${stats.isFile() ? '文件' : stats.isDirectory() ? '目录' : '其他'}`);
  console.log('文件大小(字节):', stats.size);
  console.log('最后一次修改时间:', stats.mtime.toLocaleString());
} catch (err) {
  console.error('获取文件状态失败:', err);
}

fs.Stats对象包含许多有用的属性,如:

  • .isFile():判断是否为普通文件。
  • .isDirectory():判断是否为目录。
  • .size:文件或目录占用空间的字节数(如果是目录,通常是目录本身的信息所占空间)。
  • .mtime:最后一次修改时间(modification time)的对象,可通过.getTime()获取毫秒时间戳,或.toLocaleString()获取格式化后的本地字符串。

🔥 V. 目录操作

💡 fs.mkdir() & fs.mkdirSync()

  • fs.mkdir(path[, options], callback) —— 异步创建目录。该方法接收一个必填参数路径,用于指定要创建的新目录的完整路径。还可以传入一个可选的options对象,其中可以设置权限模式或启用递归创建父目录等功能。最后一个参数是可选的回调函数,当目录创建完成后,该函数会被调用并传入错误信息(如果有)。
const fs = require('fs');

// 异步创建目录示例
fs.mkdir('./new-directory', { recursive: true }, (err) => {
  if (err) {
    console.error('创建目录失败:', err);
  } else {
    console.log('目录创建成功: new-directory');
  }
});
  • fs.mkdirSync(path[, options]) —— 同步创建目录。与异步版本相似,但它是同步执行并在出现错误时抛出异常。
try {
  fs.mkdirSync('./new-directory-sync', { recursive: true });
  console.log('目录创建成功: new-directory-sync');
} catch (err) {
  console.error('创建目录失败:', err);
}

💡 fs.rmdir() & fs.rmdirSync()

  • fs.rmdir(path, callback) —— 异步删除目录。此方法用于删除指定的空目录,若目录非空,则操作会失败。
fs.rmdir('./empty-directory', (err) => {
  if (err) {
    console.error('删除目录失败:', err);
  } else {
    console.log('空目录删除成功: empty-directory');
  }
});
  • fs.rmdirSync(path) —— 同步删除目录。与异步版本相同,但同步执行并在删除失败时抛出异常。
try {
  fs.rmdirSync('./empty-directory-sync');
  console.log('空目录删除成功: empty-directory-sync');
} catch (err) {
  console.error('删除目录失败:', err);
}

另外,Node.js 还提供了诸如 fs.readdir()(异步读取目录内容)和 fs.readdirSync()(同步读取目录内容)等方法,用于枚举指定目录中的文件和子目录。同时,还有 fs.promises.readdir() 提供基于Promise的异步API。

// 异步读取目录内容
fs.readdir('./directory', (err, files) => {
  if (err) throw err;
  console.log('目录内容:', files);
});

// 同步读取目录内容
try {
  const files = fs.readdirSync('./directory');
  console.log('目录内容:', files);
} catch (err) {
  console.error('读取目录内容失败:', err);
}

// 基于Promise的异步读取目录内容
fs.promises.readdir('./directory')
  .then(files => console.log('目录内容:', files))
  .catch(err => console.error('读取目录内容失败:', err));

借助这些方法,开发者可以在Node.js应用程序中有效地管理和操作目录结构,包括新建目录、删除空目录,以及浏览目录内文件列表。在具体应用时,同步操作适用于简单脚本或预期不会长时间阻塞的情况,而异步操作则常用于构建高性能、非阻塞的应用程序。


🌈 VI. 打开文件

💡 fs.openSync() & fs.open()

  • fs.openSync(path, flags[, mode]) —— 同步打开文件。接受三个参数:文件路径文件打开模式文件访问模式,返回一个文件描述符
  • fs.open(path, flags[, mode], callback) —— 异步打开文件。接受四个参数:文件路径文件打开模式文件访问模式回调函数
const fs = require("fs")
// 同步打开文件
try {
	const fd = fs.openSync('./test-read-async.txt', 'r');
	console.log('同步打开文件openSync-File descriptor:', fd);
	fs.readFile(fd, 'utf8', (readErr, data) => {
		if (readErr) {
			console.error('Failed to read file:', readErr);
		} else {
			console.log('File content:', data);
			// 在读取完成后记得关闭文件描述符
			fs.close(fd, closeErr => {
				if (closeErr) console.error('Failed to close file:', closeErr);
			});
		}
	});
} catch (err) {
	console.error('同步打开文件出错openSync-Error opening file:', err);
}
// 异步打开文件
fs.open('./test-read-async.txt', 'r', (err, fd) => {
	if (err) {
		console.error('异步打开文件出错open-Error opening file:', err);
	} else {
		console.log('异步打开文件open-File descriptor:', fd);
		// 假设我们在这里根据文件描述符读取文件内容
		fs.readFile(fd, 'utf8', (readErr, data) => {
			if (readErr) {
				console.error('Failed to read file:', readErr);
			} else {
				console.log('File content:', data);
				// 在读取完成后记得关闭文件描述符
				fs.close(fd, closeErr => {
					if (closeErr) console.error('Failed to close file:', closeErr);
				});
			}
		});
	}
})

⚠️ 名词解释

文件描述符:文件描述符(File Descriptor)在计算机操作系统中扮演着至关重要的角色,特别是在类Unix系统(如Linux、Mac OS X等)中。文件描述符是一种轻量级的句柄,它是操作系统内部用来跟踪和管理打开文件的一种机制。它是一个整数值,用来唯一标识进程中打开的文件或其他输入/输出资源

通过文件描述符,进程可以高效地与内核交互,执行对文件的读、写、关闭以及其他高级I/O操作,无需每次都通过文件路径去访问文件

文件打开模式(flags):用于指定如何打开和处理文件。以下是常见的文件打开模式:

/* 文件访问模式
* 'r' - 只读模式。如果文件不存在,openSync()会抛出一个错误。
* 'r+' - 读写模式。文件必须存在,否则会抛出错误。在这种模式下,你可以从文件的当前偏移位置开始读取和写入。
* 'w' - 只写模式。如果文件存在,其内容会被清空;如果文件不存在,则会被创建。
* 'w+' - 读写模式。同'w',也会清空文件内容,然后允许读取和写入。文件如果不存在会被创建。
* 'a' - 追加模式。打开文件以追加数据。如果文件不存在,会被创建。所有写入的数据都被追加到文件的末尾,不会改变已有内容。
* 'a+' - 读写追加模式。允许读取和追加数据。追加写入同'a',同时也允许从当前文件指针位置读取文件内容。
* 'x' - 创建并写入模式。如果文件已存在,则操作失败,否则创建新文件并写入。
* 'x+' - 创建并读写模式。同'x',但是也允许读取。
* 's' 和 'S'(Windows平台特有) - 打开文件并安全地同步I/O操作,防止其他进程在同一时刻访问该文件。
* */

🌟 VII. 删除文件

💡 fs.unlink() & fs.unlinkSync()

  • fs.unlink(path, callback) —— 异步删除文件。这个方法用于删除指定的文件,接收文件路径作为参数,并提供一个回调函数用于处理可能出现的错误。
fs.unlink('./test-delete-file.txt', (err) => {
  if (err) {
    console.error('删除文件失败:', err);
  } else {
    console.log('文件删除成功: test-delete-file.txt');
  }
});
  • fs.unlinkSync(path) —— 同步删除文件。同步版的删除文件方法,同样接收文件路径作为参数,但在遇到错误时会抛出异常。
try {
  fs.unlinkSync('./test-delete-file-sync.txt');
  console.log('文件删除成功: test-delete-file-sync.txt');
} catch (err) {
  console.error('删除文件失败:', err);
}

🎯 VIII. 重命名或移动文件/目录

💡 fs.rename() & fs.renameSync()

  • fs.rename(oldPath, newPath, callback) —— 异步重命名或移动文件/目录。这两个参数分别代表当前文件路径和新的目标路径,重命名或移动完成后执行回调函数。
fs.rename('./old-name.txt', './new-name.txt', (err) => {
  if (err) {
    console.error('重命名文件失败:', err);
  } else {
    console.log('文件重命名成功: old-name.txt -> new-name.txt');
  }
});
  • fs.renameSync(oldPath, newPath) —— 同步重命名或移动文件/目录。与异步版本功能相同,但在重命名或移动过程中遇到错误时会立即抛出异常。
try {
  fs.renameSync('./old-dir', './new-dir');
  console.log('目录重命名成功: old-dir -> new-dir');
} catch (err) {
  console.error('重命名目录失败:', err);
}

🗄 IX. 复制文件

由于Node.js标准库fs模块并没有直接提供复制文件的方法,但可以通过读取源文件内容后写入到目标文件实现文件复制。以下是一个简单的异步文件复制示例:

const fsPromises = require('fs').promises;

async function copyFile(src, dest) {
  try {
    const data = await fsPromises.readFile(src);
    await fsPromises.writeFile(dest, data);
    console.log(`文件复制成功: ${src} -> ${dest}`);
  } catch (err) {
    console.error('文件复制失败:', err);
  }
}

copyFile('./source.txt', './destination.txt');

对于同步版本,可以使用fs.readFileSync()fs.writeFileSync()配合实现类似功能。


🔐 X. 文件权限及所有权更改

  • fs.chmod(path, mode, callback) & fs.chmodSync(path, mode) —— 修改文件或目录的权限模式。
  • fs.chown(path, uid, gid, callback) & fs.chownSync(path, uid, gid) —— 更改文件的所有者和组ID。

这两个方法主要用于调整文件系统的权限和所有权,其中mode参数采用八进制数字表示权限(如0o755),uidgid则是用户的ID和组ID。在处理这些涉及权限的操作时务必谨慎,因为不正确的操作可能导致安全问题或服务中断。


🏁 总结

Node.js 内置的 fs 模块以其强大的文件系统功能,赋予开发者对文件和目录进行全方位管理的能力。无论是处理文本文件、目录结构,还是变更权限,fs 模块都能轻松应对:

  • 读写操作fs.readFileSync()fs.readFile() 实现异步和同步读取文件,而 fs.writeFileSync(), fs.writeFile() 以及 fs.appendFileSync()fs.appendFile() 则分别用于同步与异步写入和追加内容到文件中。异步读写能有效避免 I/O 阻塞,提升程序响应速度和并发能力。

  • 文件状态查询fs.stat()fs.statSync() 可获取文件或目录的状态信息,如类型、大小、最后修改时间等。

  • 目录管理fs.mkdir(), fs.mkdirSync() 创建目录,支持递归创建父级目录;fs.rmdir(), fs.rmdirSync() 删除空目录;fs.readdir()fs.readdirSync() 则用于读取目录内容。

  • 文件删除fs.unlink()fs.unlinkSync() 用于异步和同步删除文件。

  • 文件重命名/移动fs.rename()fs.renameSync() 支持对文件或目录进行重命名或移动操作。

  • 文件复制:尽管 fs 模块未提供直接的复制文件方法,但可以通过读取源文件内容并写入目标文件的方式来实现。

  • 权限管理fs.chmod()fs.chmodSync() 可以修改文件或目录的权限模式;fs.chown()fs.chownSync() 用于更改文件的所有者和所属组。

综合运用这些方法,Node.js 开发者可以根据实际需求灵活选择同步或异步操作,优化代码性能,确保在开发各种类型的文件系统相关应用时游刃有余。不过需要注意的是,在处理敏感操作如权限更改时,应格外小心以避免潜在的安全风险和系统稳定性问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/557315.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】string的使用

目录 1、为什么学习string类? 2、标准库中的string类 2.1 string类 2.2 string类的常见接口声明 2.2.1 string类的常见构造 ​编辑 2.2.2 string类对象的访问及遍历操作 2.2.3 string类对象的容量操作 2.2.4 string类对象的修改操作 ​编辑 1、为什么学习s…

CERLAB无人机自主框架: 2-动态目标检测与跟踪

前言:更多更新文章详见我的个人博客主页【MGodmonkeyの世界】 描述:欢迎来到CERLAB无人机自主框架,这是一个用于自主无人飞行器 (UAV) 的多功能模块化框架。该框架包括不同的组件 (模拟器,感知,映射,规划和…

gemini国内能用吗

gemini国内能用吗 虽然 Gemini 的具体功能和性能还未完全公开,但基于 Google 在 AI 领域的强大背景和技术实力,已经火出圈了,很多小伙伴已经迫不及待想了解一下它有什么优势以及如何快速使用上 首先我们来讲一下gemini的优势 多模态能力&a…

美摄智能视频创作平台,满足企业个性化的创作需求

视频已成为企业传播信息、展示品牌、吸引客户的重要手段,传统的视频制作方式往往耗时耗力,且效果不佳。美摄科技凭借其深厚的技术积累和创新能力,推出了面向企业的智能视频创作平台解决方案,助力企业轻松实现高质量的视频制作与传…

5 CatBoost模型

目录 1 背景 2 原理 2.1 类别特征处理 2.1.1 传统目标编码: TS 2.1.2 Greedy TS 2.1.3 ordered TS编码 2.1.4 CatBoost处理Categorical features总结 2.2.预测偏移处理 2.2.1 梯度无偏估计 2.3 树的构建​​​​​​​ 3 优缺点 优点 4 代码 1 背景 终于…

OpenHarmony鸿蒙南向开发案例:【智能门铃】

样例简介 智能门铃通过监控来访者信息,告诉主人门外是否有人按铃、有陌生人靠近或者无人状态。主人可以在数字管家中远程接收消息,并根据需要进行远程取消报警和一键开锁。同时,也可以通过室内屏幕获取门外状态。室内屏幕显示界面使用DevEco…

【创建型模式】单例模式

一、单例模式概述 单例模式的定义:又叫单件模式,确保一个类只有一个实例,并提供一个全局访问点。(对象创建型) 要点: 1.某个类只能有一个实例;2.必须自行创建这个实例;3.必须自行向整…

C语言 | 动态内存管理

目录: 1. 为什么要有动态内存分配 2. malloc和free 3. calloc和realloc 4. 常见的动态内存的错误 5. 动态内存经典笔试题分析 6. 柔性数组 1. 为什么要有动态内存分配 我们已经掌握的内存开辟方式有: int val 20; //在栈空间上开辟四个字节 cha…

MR-JE-70A 三菱MR-JE伺服驱动器(750W通用型)

三菱MR-JE伺服驱动器(750W通用型) MR-JE-70A外部连接,MR-JE-70A用户手册,MR-JE-70A 三相或单相AC220V三菱通用型伺服放大器750W,配套电机HG-SN52J-S100、HG-KN73J-S100。 MR-JE-70A参数说明:伺服驱动器通用型750W,三相或单相AC200V~240V 三…

C语言野指针【入门详解】

目录 一、什么是野指针 二、野指针的成因 2.1 指针未初始化 2.2 指针越界访问 2.3 指针指向的空间释放 三、如何规避野指针 3.1 初始化指针 3.2 小心越界访问 3.3 当指针不用时,及时置为空 3.4 避免返回局部变量的地址 *结语: 希望这篇关于指…

IM即时通讯软件,WorkPlus私有化部署全面支持信创环境

在数字化转型的浪潮中,政企单位对即时通讯(IM)软件的需求日益增长。然而,随着信息化程度的提高,数据安全和信息泄露风险也日益凸显。在这样的背景下,WorkPlus作为一款私有化部署的IM即时通讯软件,以其在安全性、管理便…

汇编语言——将BX中的无符号数和有符号数以二进制、八进制、十六进制、十进制形式输出

文章目录 将BX中的无符号数以二进制形式输出将BX中的无符号数以八进制形式输出将BX中的无符号数以十六进制形式输出将BX中的无符号数以十进制形式输出将BX中的有符号数以十进制形式输出 将BX中的无符号数以二进制形式输出 利用移位指令会影响CF,默认dl30h(数字0)&a…

时序深入之CPR(Clock Pessimism Removal)详解

目录 一、CPR概念 二、CPR的计算 三、CPR的开启关闭 四、CPR为0 ​五、参考资料 一、CPR概念 在时序报告的目标时钟路径中,会有一行数据clock pesssimism,第一次见可能都会对这个概念感到疑惑 同样在每条时序路径的summary中,clock pat…

自动化测试Selenium(4)

WebDriver相关api 定位一组元素 webdriver可以很方便地使用findElement方法来定位某个特定的对象, 不过有时候我们需要定位一组对象, 这时候就要使用findElements方法. 定位一组对象一般用于一下场景: 批量操作对象, 比如将页面上的checkbox都勾上. 先获取一组对象, 再在这组…

[最新]访问/加速StackOverFlow的方法

但是有很多问题都是在StackOverFlow上有现成的解决方案,而某度搜索引擎…前一页的回答互相抄袭,看着实在胀眼睛。 话不多说,解决办法: 直接访问插件商店下载插件(最快捷方便,点点就行)&#x…

Linux系统编程——权限概念和权限管理

目录 一,关于Shell 1.1 外壳程序 1.2 shell的作用 1.3 shell运行原理 二,权限概念 2.1 用户与权限 2.2 su(用户切换指令) ​编辑 2.3 提升指令权限和信任名单 三,文件权限 3.1 关于文件权限 3.2 文件访问者…

UG10.如何设置鼠标滚轮操作模型放大缩小方向?

UG10.如何设置鼠标滚轮操作模型放大缩小方向呢?看一下具体操作步骤吧。 首先打开UG10.软件,在主菜单栏选择【文件】下拉菜单,选择【实用工具】。 点击【用户默认设置】。 文章源自四五设计网-https://www.45te.com/45545.html 选中【基本环…

python语言零基础入门——变量与简单数据类型

目录 一、变量 1.创建变量 2.变量的修改 3.变量的命名 (1)常量 (2)标识符 (3)关键字 (4)命名规则 二、简单数据类型 1.变量的数据类型 2.数据类型 3.整型(In…

中断的设备树修改及上机实验(按键驱动)流程

写在前面的话:对于 GPIO 按键,我们并不需要去写驱动程序,使用内核自带的驱动程序 drivers/input/keyboard/gpio_keys.c 就可以,然后你需要做的只是修改设备树指定引脚及键值。 根据驱动文件中的platform_driver中的.of_match_tabl…

C++之类和对象三

目录 拷贝构造函数 定义铺垫 浅拷贝 深拷贝 总结 拷贝构造函数 那在创建对象时,可否创建一个与一个对象一某一样的新对象呢? 定义铺垫 构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰)&#xff0c…