模式切换
I/O 流操作
I/O 流操作
在 Node.js 中,I/O 操作非常重要,流(Stream)是处理 I/O 的一种高效方式。流可以帮助我们处理大量数据,减少内存的消耗并提高性能。流是通过 Node.js 中的 stream
模块提供的,主要分为四种类型:可读流、可写流、双工流和转换流。
流的基本概念
流(Stream)是一种抽象的数据处理方式,数据通过流从源传递到目标。流通常是基于事件驱动的,它允许我们对数据进行逐步处理而不是一次性将其载入内存。
流有以下几个基本特点:
- 按需加载:流数据是按块传输的,而不是一次性读取所有数据,避免了内存消耗过大的问题。
- 高效:在处理大量数据时,流通过分块处理和事件驱动机制,提供了更高效的数据处理方式。
了解 Buffer
在流操作中,Node.js 使用 Buffer
来处理字节数据。Buffer
是一种用于处理二进制数据的对象,它存储原始内存数据,类似于数组,但不同于普通的 JavaScript 数组,它是直接操作内存的。
创建 Buffer:
javascriptconst buf = Buffer.from('Hello, Node.js!'); console.log(buf.toString()); // 输出:Hello, Node.js!
Buffer 的用途:Buffer 用于处理文件读取、网络传输等二进制数据。
可读流的使用
可读流(Readable Stream)是从数据源中读取数据的流。常见的可读流有文件读取流、HTTP 请求等。
流的读取模式与状态
流的模式:
- 流动模式(Flowing Mode):数据自动从流中读取并触发
'data'
事件。 - 非流动模式(Paused Mode):数据不会自动流动,需要通过调用
read()
方法显式读取数据。
- 流动模式(Flowing Mode):数据自动从流中读取并触发
流的状态:
paused
:流处于暂停状态,数据不会自动流动。flowing
:流处于流动状态,数据会自动流动。
可读流的创建
可读流可以通过 stream.Readable
类或者 fs.createReadStream()
(文件读取流)等方式创建。
通过
Readable
类创建可读流:javascriptconst { Readable } = require('stream'); const readable = new Readable({ read(size) { this.push('Hello, '); this.push('world!'); this.push(null); // 标记流结束 } }); readable.on('data', (chunk) => { console.log(chunk.toString()); // 输出:Hello, world! });
通过
fs.createReadStream()
创建文件可读流:javascriptconst fs = require('fs'); const readableStream = fs.createReadStream('example.txt'); readableStream.on('data', (chunk) => { console.log(chunk.toString()); });
可读流的属性、方法及事件
常用属性:
readable
:指示流是否是可读流。readableHighWaterMark
:指示流的高水位标记,决定了流的内部缓冲区大小。
常用方法:
read(size)
:从流中读取指定大小的数据。pipe(destination)
:将可读流的数据传递给目标可写流。
常用事件:
'data'
:每次读取到数据时触发。'end'
:流结束时触发。'error'
:发生错误时触发。
可读流的常见操作
从流中读取数据并处理:
javascriptconst fs = require('fs'); const readableStream = fs.createReadStream('example.txt'); readableStream.on('data', (chunk) => { console.log(`Received ${chunk.length} bytes of data.`); }); readableStream.on('end', () => { console.log('Stream finished!'); });
使用
pipe()
方法将可读流传递给可写流:javascriptconst fs = require('fs'); const readableStream = fs.createReadStream('example.txt'); const writableStream = fs.createWriteStream('output.txt'); readableStream.pipe(writableStream);
可写流的使用
可写流(Writable Stream)是向数据目标写入数据的流。常见的可写流有文件写入流、HTTP 响应流等。
可写流的创建
通过
Writable
类创建可写流:javascriptconst { Writable } = require('stream'); const writable = new Writable({ write(chunk, encoding, callback) { console.log(`Writing: ${chunk.toString()}`); callback(); } }); writable.write('Hello, '); writable.write('world!'); writable.end();
通过
fs.createWriteStream()
创建文件可写流:javascriptconst fs = require('fs'); const writableStream = fs.createWriteStream('output.txt'); writableStream.write('Hello, Node.js!'); writableStream.end();
可写流的属性、方法及事件
常用属性:
writable
:指示流是否是可写流。writableHighWaterMark
:指示流的高水位标记,决定了流的内部缓冲区大小。
常用方法:
write(chunk, encoding, callback)
:将数据写入流。end()
:标记流结束。
常用事件:
'drain'
:缓冲区已清空,可以继续写入。'finish'
:所有数据都已写入并关闭流。
可写流的常见操作
向流中写入数据:
javascriptconst fs = require('fs'); const writableStream = fs.createWriteStream('output.txt'); writableStream.write('Hello, '); writableStream.write('Node.js!'); writableStream.end();
通过
pipe()
方法将可读流传递给可写流:javascriptconst fs = require('fs'); const readableStream = fs.createReadStream('example.txt'); const writableStream = fs.createWriteStream('output.txt'); readableStream.pipe(writableStream);
双工流与转换流介绍
双工流(Duplex Stream)
双工流是既可以读取数据又可以写入数据的流。例如,net.Socket
是一个双工流,它既可以接收数据,也可以发送数据。
创建双工流:
javascriptconst { Duplex } = require('stream'); const duplexStream = new Duplex({ read(size) { this.push('Hello, '); this.push('world!'); this.push(null); // 标记流结束 }, write(chunk, encoding, callback) { console.log(`Writing: ${chunk.toString()}`); callback(); } }); duplexStream.write('Test data'); duplexStream.on('data', (chunk) => { console.log(`Received: ${chunk.toString()}`); });
转换流(Transform Stream)
转换流是一种特殊类型的双工流,它可以在读取数据时进行转换,也可以在写入数据时进行转换。例如,压缩流、解压缩流、加密流等都是转换流。
创建转换流:
javascriptconst { Transform } = require('stream'); const transformStream = new Transform({ transform(chunk, encoding, callback) { this.push(chunk.toString().toUpperCase()); callback(); } }); process.stdin.pipe(transformStream).pipe(process.stdout);
在上述示例中,transformStream
将输入流中的所有数据转换为大写字母后输出。