前言
最近在使用express-generator知识进行搭建前后端通信,其中有些知识点涉及到nodejs的fs和path核心模块,因此另写一篇文章进行介绍和代码案例练习。
fs
(文件系统)和path
是 Node.js 的核心模块,用于文件操作和路径处理。
一、fs讲解
1.
fs.readFile
和fs.writeFile
fs.readFile(path[, options], callback)
:异步读取文件内容。fs.writeFile(path, data[, options], callback)
:异步写入文件。
案例练习
先看目录
static文件夹用于存放内容(此时aa.txt和bb.txt均为空)
fs_demo.js用于代码撰写
//fs_demo.js
const fs = require('fs');
// 异步读取文件
fs.readFile('./static/aa.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
// 异步写入文件
fs.writeFile('./static/aa.txt', 'Hello World!', 'utf8', (err) => {
if (err) throw err;
console.log('写入已被保存!');
});
打开文件的终端,执行终端
node fs_demo.js
再打开aa.txt进行检查,此时发现"Hello World!"已被成功写入。
2.
fs.readFileSync
和fs.writeFileSync
fs.readFileSync(path[, options])
:同步读取文件内容。fs.writeFileSync(path, data[, options])
:同步写入文件。
仍然是fs_demo.js(只是代码不同)这次操作的是bb.txt。
const fs = require('fs');
// 同步读取文件
try {
const data = fs.readFileSync('./static/bb.txt', 'utf8');
console.log(data);
} catch (err) {
console.error(err);
}
// 同步写入文件
try {
fs.writeFileSync('./static/bb.txt', 'Hello NODEJS!', 'utf8');
console.log('内容已写入bb.txt!');
} catch (err) {
console.error(err);
}
执行文件
node fs_demo.js
执行成功,并打开bb.txt进行检查。
3.关于同步和异步的理解
在 Node.js 中,
fs
模块提供了同步和异步两种方法来处理文件系统操作。选择使用同步还是异步方法取决于应用需求、性能考量和错误处理策略。
以下是一些指导原则:
异步方法
何时使用异步方法:
非阻塞操作:当您不希望文件操作阻塞事件循环时,应使用异步方法。这有助于保持应用程序的响应性,特别是在处理大量文件或大文件时。
I/O 密集型应用:在 I/O 密集型应用中,如文件服务器或数据流处理,异步方法可以提高吞吐量和效率。
用户界面响应:在需要保持用户界面响应的应用(如命令行工具或图形界面应用)中,异步方法可以避免界面冻结。
并发操作:当您需要同时执行多个文件操作,并且希望它们并发运行时,异步方法更加合适。
错误处理:如果您希望在发生错误时立即处理,而不是等待整个操作完成,异步方法允许您在回调函数中立即捕获和处理错误。
同步方法
何时使用同步方法:
脚本和简单应用:在简单的脚本或小型应用中,同步方法可以简化代码,因为它们不需要回调函数。
初始化操作:在应用程序启动时进行的文件操作,如配置文件加载,可以使用同步方法,因为这些操作通常需要在程序继续之前完成。
顺序依赖操作:当一个操作的输出是下一个操作的输入,并且它们之间存在严格的顺序依赖时,同步方法可以确保操作按顺序执行。
测试和调试:在测试和调试阶段,同步方法可以提供更直观的控制流,使得问题更容易追踪和解决。
性能要求不高的场景:在文件操作对性能影响不大,或者文件很小的情况下,同步方法可以简化代码实现。
简单记忆和使用
在实际应用中,异步方法通常是首选,因为它们不会阻塞 Node.js 的事件循环,这对于保持高性能和良好的用户体验至关重要。
然而,在某些情况下,同步方法的简单性和直接性可能更适合特定的需求。
4.
fs.appendFile
和fs.appendFileSync
fs.appendFile(path, data[, options], callback)
:异步追加文件。fs.appendFileSync(path, data[, options])
:同步追加文件。
异步追加文件
(在上述演示的异步读取、写入的案例中新增一个异步追加)
为了方便观察,这里我们把aa.txt内容清空。
注意文件路径
//fs_demo.js
const fs = require('fs');
// 异步读取文件
fs.readFile('./static/aa.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
// 异步写入文件
fs.writeFile('./static/aa.txt', 'Hello World!\n', 'utf8', (err) => {
if (err) throw err;
console.log('写入已被保存!');
});
// 异步追加文件
fs.appendFile('./static/aa.txt', '这是新追加的内容\n', (err) => {
if (err) throw err;
console.log('内容已追加到aa.txt中');
});
执行文件:node fs_demo.js
同步追加文件
//fs_demo.js
const fs = require('fs');
// 同步读取文件
try {
const data = fs.readFileSync('./static/bb.txt', 'utf8');
console.log(data);
} catch (err) {
console.error(err);
}
// 同步写入文件
try {
fs.writeFileSync('./static/bb.txt', 'Hello NODEJS!', 'utf8');
console.log('内容已写入bb.txt!');
} catch (err) {
console.error(err);
}
// 同步追加文件
try {
fs.appendFileSync('./static/bb.txt', '\n新增内容Hello BB.TXT');
console.log('内容已追加到bb.txt');
} catch (err) {
console.error(err);
}
执行文件
5.关于写入和追加的注意点
文件写入(
write
)
- 行为:文件写入操作会覆盖文件指定位置之后的内容。如果文件不存在,写入操作会创建新文件。如果文件存在,写入操作会从指定的文件位置开始写入数据,覆盖原有数据。
- 用途:当你需要完全替换文件内容或者从文件的特定位置开始写入新数据时,使用写入操作。
- 影响:如果写入位置在文件中间,写入的数据会替换掉该位置之后的所有数据,导致原有数据丢失。
文件追加(
append
)
- 行为:文件追加操作会在文件的末尾添加数据,不会影响文件之前的内容。如果文件不存在,追加操作会创建新文件。
- 用途:当你需要在文件末尾添加数据,而不需要修改或删除原有数据时,使用追加操作。
- 影响:追加操作不会影响文件的现有内容,只会增加新数据到文件末尾。
书写位置的先后对文件的影响
书写位置的先后顺序对文件内容有直接影响,尤其是在不使用追加模式的情况下:
先写入后追加:
- 如果先写入文件,然后再追加文件,追加的数据会被添加到写入数据之后。如果写入操作覆盖了文件的末尾,追加的数据将跟在新写入的数据之后。
- 例如,如果一个文件包含内容 "Hello",先写入 "World",然后追加 "!",最终文件内容将是 "World!"。
先追加后写入:
- 如果先追加文件,然后再写入文件,写入操作会覆盖追加的内容,如果写入位置在追加内容之前。
- 例如,如果一个文件包含内容 "Hello",先追加 "!",然后写入 "World",最终文件内容将是 "World",追加的 "!" 将被覆盖。
6.
fs.exists
和fs.existsSync
fs.exists(path, callback)
:检查文件是否存在(已废弃)。fs.existsSync(path)
:同步检查文件是否存在(推荐使用fs.stat
或fs.access
)。
代码案例(注意文件路径)
//fs_demo.js
const fs = require('fs');
// 同步检查文件是否存在
if (fs.existsSync('./static/aa.txt')) {
console.log('File exists');
} else {
console.log('File does not exist');
}
这里是检查utils/static文件夹下的aa.txt文件是否存在,因为我们在此之前已经创建aa.txt了,所以是存在的。
二、path讲解
1.
path.join
path.join([...paths])
:连接路径片段,自动处理路径分隔符。2.
path.resolve
path.resolve([...paths])
:解析路径,返回绝对路径。3.
path.basename
,path.dirname
,path.extname
path.basename(path[, ext])
:获取路径的基本名称(文件名)。path.dirname(path)
:获取路径的目录名。path.extname(path)
:获取路径的扩展名。
代码演示
代码写在utils/path_test.js
//path_test.js
const path = require('path');
const filePath = path.join(__dirname, '../utils/path_test.js');
console.log("path_test.js的__dirname>>>",__dirname);
console.log("path_test.js的__filename>>>",__filename);
console.log("当前文件path_test.js的绝对地址>>>",filePath);
console.log(__filename==filePath);
console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
const absolutePath = path.resolve(__dirname, './utils/static/aa.txt');
console.log("aa.txt的绝对路径>>>",absolutePath);
console.log("<<<<<<<<<<<<<<<<<<<<");
const filePath3 = path.join(__dirname,'./utils/static/bb.txt');
console.log("bb.txt的文件名",path.basename(filePath3));
console.log("bb.txt所在目录",path.dirname(filePath3));
console.log("bb.txt的文件扩展",path.extname(filePath3));
总结
至此,nodejs的核心模块fs和path已讲解完毕,并给出一些练习案例。大家也可以尝试将知识点综合使用到一起。比如:
用fs进行文件读取、写入、追加的时候,我们可以通过path模块,获取目标文件的路径,和fs结合使用。
如果你喜欢这篇文章,可以点赞收藏。
关注我,了解更多前端实用知识。