Skip to content
一、文件操作
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

stream.png

  • 代码演示

    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);
  • 写日志

    js
    const 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 文件,继续积累日志
      • 用法

        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
  • 日志分析

    • 如针对 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)
      })

Released under the MIT License.