一、文件操作
1. node 自带的文件写入
- 问题一旦文件很大,存在很大的问题
- 代码演示js
const fs = require('fs'); const path = require('path'); const fileName = path.resolve(__dirname, 'data.txt'); // 读取文件内容 fs.readFile(fileName, (err, data) => { if (err) { console.error(err); return } // data 是二进制类型 console.log(data.toString()); }); // 写入文件 const content = "这是新写入的内容"; const opt = { flag: 'a' // 追加写入、覆盖用 w } fs.writeFile(fileName, content, opt, (err) => { console.error(err); }); // 判断文件是否存在 fs.exists(fileName, (exist) => { console.log('exist', exist) })
2. IO操作的性能瓶颈
- IO 包括"网络IO" 和 "文件IO"
- 相比于CPU计算和内存读写,IO 的突出特点就是慢
- 如何在有限的硬件资源下提高 IO 的操作效率
3. stream
代码演示
js// 示例一:标准的输入输出 process.stdin.pipe(process.stdout) // 示例二: 请求 const http = require('http'); const server = http.createServer((req, res) => { if (req.method === 'POST') { req.pipe(res); } }) server.listen(8000); // 示例三: 操作文件 拷贝文件 const fs = require('fs'); const path = require('path'); const fileName1 = path.resolve(__dirname, 'data.txt'); const fileName2 = path.resolve(__dirname, 'data-bak.txt'); // 读取文件的 stream 对象 const readStream = fs.createReadStream(fileName1); // 写入文件的 stream 对象 const writeStream = fs.createWriteStream(fileName2); // 拷贝,通过 pipe readStream.pipe(writeStream); // 数据读取完成,即拷贝完成 readStream.on('end', function () { console.log('拷贝完成') }) // 示例四: 请求读取文件的内容 const http = require('http'); const fs = require('fs'); const path = require('path'); const server = http.createServer((req, res) => { if (req.method === 'GET') { const fileName = path.resolve(__dirname, 'data.txt'); const stream = fs.createReadStream(fileName); // 将 res 作为 stream 的 dest stream.pipe(res); } }) server.listen(8000);
写日志
jsconst fs = require('fs'); const path = require('path'); // 写日志 function writeLog(writeStream, log) { writeStream.write(log + '\n'); } // 生成 write stream function createWriteStream(fileName) { const fullFileName = path.join(__dirname, '../', '../', 'logs', fileName); const writeStream = fs.createWriteStream(fullFileName, { flags: 'a' }); return writeStream; } // 写访问日志 const accessWriteStream = createWriteStream('access.log'); function access(log) { writeLog(accessWriteStream, log) } module.exports = { access }
日志拆分
- 日志内容会慢慢积累,放在一个文件中不好处理
- 按时间划分日志文件,如 2022-04-10.access.log
- 实现方式:linux 的 crontab 命令,即定时任务
crontab
- 设置定时任务,格式:***** command
- 第一个* 分钟
- 第二个* 小时
- 第三个* 日期
- 第四个* 月份
- 第五个* 星期几
- 将 access.log 拷贝并冲命名为 2022-04-10.access.log
- 清空 access.log 文件,继续积累日志
- 设置定时任务,格式:***** command
用法
shell# 打开编辑 * 0 * * * sh xxxx/xxx.sh crontab -e # 查看 crontab -l
- sh 编写sh
#!/usr/bin/sh cd /Users/yangdong/vitepress-docs/docs/node/blog/nodejs cp data.txt $(date +%Y-%m-%d-%H).access.log echo "" > data.txt
- sh 编写
日志分析
- 如针对 access.log 日志,分析 chrome 的占比
- 日志是按行存储的,一行就是一条日志
- 使用 nodejs 的 readline (基于 stream, 效率高)js
const fs = require('fs'); const path = require('path'); const readline = require('readline'); // 文件名 const fileName = path.join(__dirname, '../', '../', 'logs', 'access.log'); // 创建 read stream const readStream = fs.createReadStream(fileName); // 创建 readline 对象 const rl = readline.createInterface({ input: readStream }) let chromeNum = 0; let sum = 0; // 逐行读取 rl.on('line', (lineData) => { if (!lineData) return; // 总行数 sum ++; const arr = lineData.split("--"); if (arr[2]?.indexOf('Chrome') > 0) { // 累加 chromeNum ++ } }) // 监听读取完成 rl.on('close', () => { console.log('chrome占比---->', chromeNum / sum) })