node中的fs模块常用操作

Node.js的fs模块是文件系统操作的核心工具,提供了丰富的API用于处理文件和目录。本文将系统讲解常用操作,并提供可直接复用的代码示例。

一、文件操作

1.异步读取文件 readFile()

1
2
3
4
5
6
7
8
// 导入fs模块
const fs = require('fs');

// 从test.txt文件中读取数据至data中
fs.readFile('test.txt', 'utf8', (err, data) => {
if (err) return console.error(err);
console.log(data);
});

2.同步读取文件(阻塞主线程) readFileSync()

1
2
3
4
5
6
7
8
9
10
// 导入fs模块
const fs = require('fs');

// 从test.txt文件中读取保存至data中
try {
const data = fs.readFileSync('test.txt', 'utf8');
console.log(data);
} catch (err) {
console.error(err);
}

3. 异步写入文件 writeFile()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 导入fs模块
const fs = require('fs');

// 覆盖写入
fs.writeFile('output.txt', 'Hello Node.js!', (err) => {
if (err) return console.error(err);
console.log(' 写入成功');
});

// 追加写入
fs.appendFile('output.txt', '\n追加内容', (err) => {
if (err) return console.error(err);
console.log(' 追加成功');
});

4. 同步写入文件 writeFileSync()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 导入fs模块
const fs = require('fs');

// 同步覆盖写入(阻塞)
try {
fs.writeFileSync('sync.txt', '同步覆盖写入内容');
console.log(' 同步覆盖写入成功');
} catch (err) {
console.error(err);
}

// 同步追加写入(阻塞)
try {
fs.appendFileSync('sync.txt', '同步追加写入内容');
console.log(' 同步追加写入成功');
} catch (err) {
console.error(err);
}

二、目录操作

1. 创建目录 mkdir()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 导入fs模块
const fs = require('fs');

// 异步创建目录
fs.mkdir('uploads', { recursive: true }, (err) => {
if (err) return console.error(err);
console.log(' 目录创建成功');
});

// 同步创建目录
try {
fs.mkdirSync('uploads_sync', { recursive: true });
console.log(' 同步目录创建成功');
} catch (err) {
console.error(err);
}

2. 读取目录内容 readdirSync()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 导入fs模块
const fs = require('fs');

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

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

3. 删除目录 rmdir()

1
2
3
4
5
6
7
8
9
// 导入fs模块
const fs = require('fs');

// 异步删除空目录
fs.rmdir('uploads', (err) => {
if (err) return console.error(err);
console.log(' 目录删除成功');
});

1
2
3
4
5
// 递归删除非空目录 以对象的形式添加第二个参数:{recursive:true}
fs.rmdir('uploads', {recursive:true} ,(err) => {
if (err) return console.error(err);
console.log(' 目录删除成功');
});

三、流处理(大文件操作)

1. 读取流

1
2
3
4
5
6
7
// 导入fs模块
const fs = require('fs');

const readStream = fs.createReadStream('largefile.mp4');
readStream.on('data', (chunk) => {
console.log(` 读取到 ${chunk.length} 字节`);
});

2. 写入流

1
2
3
4
5
6
// 导入fs模块
const fs = require('fs');

const writeStream = fs.createWriteStream('output.mp4');
writeStream.write(' 文件头数据');
writeStream.end(' 文件尾数据');

3. 管道流复制文件

1
2
3
4
5
6
7
8
9
// 导入fs模块
const fs = require('fs');

// 复制文件
const rs = fs.createReadStream('source.txt');
const ws = fs.createWriteStream('destination.txt');
rs.pipe(ws).on('finish', () => {
console.log(' 复制完成');
});

四、错误处理

1. 异步操作错误处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 导入fs模块
const fs = require('fs');

fs.readFile('nonexistent.txt', (err, data) => {
if (err) {
if (err.code === 'ENOENT') {
console.log(' 文件不存在');
} else {
console.error(' 读取错误:', err);
}
return;
}
console.log(data);
});

2. 同步操作错误处理

1
2
3
4
5
6
7
8
9
// 导入fs模块
const fs = require('fs');

try {
const stats = fs.statSync('test.txt');
console.log(stats.isFile());
} catch (err) {
console.error(' 同步错误:', err);
}

五、最佳实践

  1. 优先使用异步方法:避免阻塞事件循环(如readFile优于readFileSync)。
  2. 流处理大文件:避免内存溢出,推荐使用createReadStreampipe
  3. 权限控制:通过mode参数设置文件权限(如0o666表示读写权限)。
  4. 路径处理:结合path模块处理跨平台路径问题。

总结

本文覆盖了fs模块的核心操作,包括文件读写、目录管理、流处理及错误处理。通过示例代码可快速上手,建议在实际项目中结合path模块和异步编程模式优化性能。更多细节可参考Node.js官方文档

四则运算算法实现

四则运算

1. 中缀表达式转后缀表达式

中缀表达式 9+(3-1)×3+10÷2 转化为后缀表达式 9 3 1 - 3 * + 10 2 / +

规则

  1. 遇到数字就直接输出到后缀表达式中,遇到操作符就判断其优先级,并将其压入栈中。
  2. 如果栈顶元素的优先级大于等于当前操作符,则先将栈顶元素弹出并输出到后缀表达式中,再将当前操作符压入栈中。
  3. 如果遇到了左括号,则直接将其压入栈中,如果遇到了右括号,则弹出栈中的元素,直到遇到了左括号为止,并将这些元素输出到后缀表达式中。
  4. 最后,将栈中剩余的元素依次弹出,并输出到后缀表达式中。

演示

  1. 初始化一空栈,用来对符号进出栈使用。
  2. 第一个字符是数字9,输出9,后面是符号“+”,进栈。
  3. 第三个字符是“(”,依然是符号,因其只是左括号,还未配对,故进栈。
  4. 第四个字符是数字3,输出,总表达式为93,接着是“-”,进栈。
  5. 接下来是数字1,输出,总表达式为 9 3 1,后面是符号“)”,此时,我们需要去匹配 此前的“(”,所以栈顶依次出栈,并输出,直到“(”出栈为止。此时左括号上方只有“-”, 因此输出“-”。总的输出表达式为 9 3 1 -。
  6. 紧接着是符号“×”,因为此时的栈顶符号为“+”号,优先级低于“×”,因此不输出,“×”进栈。接着是数字3,输出,总的表达式为 9 3 1 - 3。
  7. 之后是符号“+”,此时当前栈顶元素“×”比这个“+”的优先级高,因此栈中元素出栈并输出(没有比“+”号更低的优先级时一直出栈,所以全部出栈),总输出表达式为9 3 1 - 3 × +。然后将当前这个符号“+”进栈。也就是说,前6张图的栈底的“+”是指中缀表达式中开头的9 后面那个“+”,而下图的左图中的栈底(也是栈顶)的“+”是指“9+(3-1)×3+”中的最后 一个“+”。
  8. 紧接着数字10,输出,总表达式变为9 3 1 - 3 × + 10。后是符号“÷”,所以“/”进栈。
  9. 最后一个数字2,输出,总的表达式为9 3 1 - 3 × + 10 2。
  10. 因已经到最后,所以将栈中符号全部出栈并输出。最终输出的后缀表达式结果为 9 3 1 - 3 × + 10 2 / +。

2. 后缀表达式计算结果

规则

  1. 遍历后缀表达式,如果遇到数字则直接入栈,如果遇到操作符,则弹出栈顶的两个元素,进行计算后将结果入栈。
  2. 最终,栈内剩余的元素就是整个表达式的计算结果。

演示

  1. 初始化一个空栈。此栈用来对要运算的数字进出使用。
  2. 后缀表达式中前三个都是数字,所以9、3、1进栈。
  3. 接下来是“-”,所以将栈中的1出栈作为减数,3出栈作为被减数,并运算3-1得到 2,再将2进栈。
  4. 接着是数字3进栈。
  5. 后面是“*”,也就意味着栈中3和2出栈,2与3相乘,得到6,并将6进栈。
  6. 下面是“+”,所以栈中6和9出栈,9与6相加,得到15,将15进栈。
  7. 接着是10与2两数字进栈。
  8. 接下来是符号“/”,因此,栈顶的2与10出栈,10与2相除,得到5,将5进栈。
  9. 最后一个是符号“+”,所以15与5出栈并相加,得到20,将20进栈。
  10. 结果是20出栈,栈变为空。

参考案例

开篇寄语

开篇寄语 🙏

从今天起,我就开始着手准备写自己的博客了,把自己的一些想法,心得,给记录下来。
以前,无论是学习还是做一些小项目,都是零零散散的,没有进行一个很好的归纳与总结,这就导致最终都没有很好的形成一个系统的知识框架,所以这个博客站,就此产生了,我会努力坚持更新这个博客站,尽管以后的更新内容会很杂(本人学的东西很杂,😂)。