Node.js中Stream模块详解

Node.js 中 Stream 模块全部 API 详解

一、Stream 基础概念

javascript 复制代码
const { Stream } = require('stream');

// 1. Stream 类型
// - Readable: 可读流
// - Writable: 可写流
// - Duplex: 双工流
// - Transform: 转换流

// 2. Stream 事件
// - data: 数据可读时触发
// - end: 数据读取完成时触发
// - error: 发生错误时触发
// - finish: 数据写入完成时触发
// - close: 流关闭时触发
// - pipe: 流被管道连接时触发
// - unpipe: 流取消管道连接时触发

二、Readable 流

javascript 复制代码
const { Readable } = require('stream');

// 1. 创建可读流
class MyReadable extends Readable {
  constructor(options) {
    super(options);
    this.data = ['a', 'b', 'c'];
  }

  _read() {
    const chunk = this.data.shift();
    if (chunk) {
      this.push(chunk);
    } else {
      this.push(null);  // 结束流
    }
  }
}

// 2. 使用可读流
const readable = new MyReadable();
readable.on('data', (chunk) => {
  console.log('收到数据:', chunk);
});
readable.on('end', () => {
  console.log('数据读取完成');
});

// 3. 暂停和恢复
readable.pause();  // 暂停读取
readable.resume();  // 恢复读取

// 4. 销毁流
readable.destroy();  // 销毁流

// 5. 设置编码
readable.setEncoding('utf8');  // 设置编码

// 6. 取消管道连接
readable.unpipe();  // 取消所有管道连接
readable.unpipe(writable);  // 取消特定管道连接

// 7. 检查流状态
console.log('是否可读:', readable.readable);
console.log('是否暂停:', readable.isPaused());

三、Writable 流

javascript 复制代码
const { Writable } = require('stream');

// 1. 创建可写流
class MyWritable extends Writable {
  constructor(options) {
    super(options);
  }

  _write(chunk, encoding, callback) {
    console.log('写入数据:', chunk);
    callback();  // 写入完成
  }

  _final(callback) {
    console.log('写入完成');
    callback();
  }
}

// 2. 使用可写流
const writable = new MyWritable();
writable.write('Hello');  // 写入数据
writable.end('World');  // 写入数据并结束流

// 3. 设置编码
writable.setDefaultEncoding('utf8');  // 设置默认编码

// 4. 检查流状态
console.log('是否可写:', writable.writable);
console.log('是否已结束:', writable.writableEnded);
console.log('是否已完成:', writable.writableFinished);

// 5. 销毁流
writable.destroy();  // 销毁流

// 6. 清空缓冲区
writable.cork();  // 暂停写入
writable.uncork();  // 恢复写入

四、Duplex 流

javascript 复制代码
const { Duplex } = require('stream');

// 1. 创建双工流
class MyDuplex extends Duplex {
  constructor(options) {
    super(options);
    this.data = ['a', 'b', 'c'];
  }

  _read() {
    const chunk = this.data.shift();
    if (chunk) {
      this.push(chunk);
    } else {
      this.push(null);
    }
  }

  _write(chunk, encoding, callback) {
    console.log('写入数据:', chunk);
    callback();
  }
}

// 2. 使用双工流
const duplex = new MyDuplex();
duplex.on('data', (chunk) => {
  console.log('收到数据:', chunk);
});
duplex.write('Hello');
duplex.end();

五、Transform 流

javascript 复制代码
const { Transform } = require('stream');

// 1. 创建转换流
class MyTransform extends Transform {
  constructor(options) {
    super(options);
  }

  _transform(chunk, encoding, callback) {
    // 转换数据
    const transformed = chunk.toString().toUpperCase();
    this.push(transformed);
    callback();
  }

  _flush(callback) {
    // 流结束时的处理
    this.push('END');
    callback();
  }
}

// 2. 使用转换流
const transform = new MyTransform();
transform.on('data', (chunk) => {
  console.log('转换后数据:', chunk);
});
transform.write('hello');
transform.end();

六、管道操作

javascript 复制代码
const { Readable, Writable } = require('stream');

// 1. 基本管道操作
readable.pipe(writable);

// 2. 链式管道
readable
  .pipe(transform1)
  .pipe(transform2)
  .pipe(writable);

// 3. 管道事件
readable.on('pipe', (source) => {
  console.log('开始管道连接');
});
writable.on('unpipe', (source) => {
  console.log('取消管道连接');
});

// 4. 错误处理
readable.on('error', (err) => {
  console.error('读取错误:', err);
});
writable.on('error', (err) => {
  console.error('写入错误:', err);
});

七、实用工具函数

javascript 复制代码
const { pipeline, finished } = require('stream');

// 1. pipeline 函数
pipeline(
  readable,
  transform,
  writable,
  (err) => {
    if (err) {
      console.error('管道错误:', err);
    } else {
      console.log('管道完成');
    }
  }
);

// 2. finished 函数
finished(readable, (err) => {
  if (err) {
    console.error('流结束错误:', err);
  } else {
    console.log('流正常结束');
  }
});

八、实际应用示例

javascript 复制代码
const { Readable, Writable, Transform } = require('stream');
const fs = require('fs');
const zlib = require('zlib');

// 1. 文件流操作
// 读取文件
const readStream = fs.createReadStream('input.txt');
// 写入文件
const writeStream = fs.createWriteStream('output.txt');
// 管道连接
readStream.pipe(writeStream);

// 2. 压缩文件
const gzip = zlib.createGzip();
fs.createReadStream('input.txt')
  .pipe(gzip)
  .pipe(fs.createWriteStream('output.txt.gz'));

// 3. 解压文件
const gunzip = zlib.createGunzip();
fs.createReadStream('input.txt.gz')
  .pipe(gunzip)
  .pipe(fs.createWriteStream('output.txt'));

// 4. 自定义转换流
class UppercaseTransform extends Transform {
  _transform(chunk, encoding, callback) {
    this.push(chunk.toString().toUpperCase());
    callback();
  }
}

// 5. 流式数据处理
const processData = new UppercaseTransform();
fs.createReadStream('input.txt')
  .pipe(processData)
  .pipe(fs.createWriteStream('output.txt'));

// 6. 错误处理
processData.on('error', (err) => {
  console.error('处理错误:', err);
});

// 7. 流控制
let paused = false;
processData.on('data', (chunk) => {
  if (paused) {
    processData.pause();
  }
});

// 8. 内存管理
const CHUNK_SIZE = 1024 * 1024;  // 1MB
fs.createReadStream('large-file.txt', { highWaterMark: CHUNK_SIZE })
  .pipe(fs.createWriteStream('output.txt'));

九、高级特性

javascript 复制代码
const { Readable, Writable, Transform } = require('stream');

// 1. 背压处理
class BackpressureWritable extends Writable {
  constructor(options) {
    super(options);
    this.highWaterMark = options.highWaterMark || 16384;
  }

  _write(chunk, encoding, callback) {
    // 检查缓冲区大小
    if (this.writableLength >= this.highWaterMark) {
      // 暂停读取
      this.emit('drain');
      callback(new Error('背压'));
    } else {
      // 继续写入
      callback();
    }
  }
}

// 2. 自定义缓冲区
class CustomBuffer extends Transform {
  constructor(options) {
    super(options);
    this.buffer = Buffer.alloc(0);
  }

  _transform(chunk, encoding, callback) {
    // 添加到缓冲区
    this.buffer = Buffer.concat([this.buffer, chunk]);
    
    // 处理完整的数据块
    while (this.buffer.length >= 1024) {
      const data = this.buffer.slice(0, 1024);
      this.buffer = this.buffer.slice(1024);
      this.push(data);
    }
    
    callback();
  }

  _flush(callback) {
    // 处理剩余数据
    if (this.buffer.length > 0) {
      this.push(this.buffer);
    }
    callback();
  }
}

// 3. 流组合
class StreamComposer extends Transform {
  constructor(streams) {
    super();
    this.streams = streams;
  }

  _transform(chunk, encoding, callback) {
    // 处理多个流
    let result = chunk;
    for (const stream of this.streams) {
      result = stream._transform(result, encoding);
    }
    this.push(result);
    callback();
  }
}

// 4. 流监控
class StreamMonitor extends Transform {
  constructor(options) {
    super(options);
    this.stats = {
      bytesProcessed: 0,
      chunksProcessed: 0,
      startTime: Date.now()
    };
  }

  _transform(chunk, encoding, callback) {
    // 更新统计信息
    this.stats.bytesProcessed += chunk.length;
    this.stats.chunksProcessed++;
    
    // 输出统计信息
    console.log('处理统计:', this.stats);
    
    this.push(chunk);
    callback();
  }
}

十、最佳实践

javascript 复制代码
const { Readable, Writable, Transform } = require('stream');

// 1. 错误处理
function handleStreamError(stream, error) {
  console.error('流错误:', error);
  stream.destroy();
}

// 2. 资源清理
function cleanupStream(stream) {
  stream.removeAllListeners();
  stream.destroy();
}

// 3. 性能优化
function optimizeStream(stream, options) {
  stream.setMaxListeners(options.maxListeners || 10);
  stream.setEncoding(options.encoding || 'utf8');
}

// 4. 流控制
function controlStream(stream, options) {
  const { highWaterMark, lowWaterMark } = options;
  
  stream.on('drain', () => {
    console.log('缓冲区已清空');
  });
  
  stream.on('error', (err) => {
    console.error('流错误:', err);
  });
}

// 5. 流组合
function composeStreams(streams) {
  return streams.reduce((prev, curr) => {
    return prev.pipe(curr);
  });
}

// 6. 流监控
function monitorStream(stream) {
  const stats = {
    startTime: Date.now(),
    bytesProcessed: 0,
    chunksProcessed: 0
  };
  
  stream.on('data', (chunk) => {
    stats.bytesProcessed += chunk.length;
    stats.chunksProcessed++;
  });
  
  stream.on('end', () => {
    const duration = Date.now() - stats.startTime;
    console.log('流统计:', {
      ...stats,
      duration,
      throughput: stats.bytesProcessed / duration
    });
  });
  
  return stats;
}

Stream 模块的主要特点:

  1. 提供流式数据处理能力
  2. 支持多种流类型
  3. 提供丰富的操作方法
  4. 高效的内存管理
  5. 支持背压处理

使用建议:

  1. 正确处理错误
  2. 注意内存使用
  3. 合理使用背压
  4. 及时清理资源
  5. 监控流性能
相关推荐
没事别瞎琢磨7 分钟前
八、环境隔离——构建安全的子进程环境
人工智能·node.js
没事别瞎琢磨1 小时前
六、输出捕获与截断
人工智能·node.js
没事别瞎琢磨1 小时前
七、敏感路径预检——Protected Paths
人工智能·node.js
没事别瞎琢磨1 小时前
五、进程执行——spawn、超时与进程树清理
人工智能·node.js
没事别瞎琢磨1 小时前
四、命令风险分级与审批策略
人工智能·node.js
没事别瞎琢磨2 小时前
三、配置系统——默认值与解析
人工智能·node.js
右耳朵猫AI3 小时前
Node.js周刊2026W22 | Node.js 26、Deno 2.8、Rolldown 1.0、TypeORM 1.0、Bun v1.3.14
node.js
没事别瞎琢磨3 小时前
二、类型系统——给所有概念起名字
人工智能·node.js
Java.熵减码农6 小时前
Hermes Agent 安装踩坑记录:DNS 解析失败 & Node.js 幽灵文件冲突
node.js·ai编程·hermes
接着奏乐接着舞。6 小时前
Node.js 掌握度 20 题自测水平
node.js