”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 流:Node.js

流:Node.js

发布于2024-11-01
浏览:909

Streams: Node.js

Node.js 中的流完整指南

Node.js 中的流是一种以连续方式处理数据读写的强大方法。它们使您能够有效地处理数据,特别是在处理大量信息或 I/O 操作时。本指南将介绍流的类型、如何使用它们以及实际示例,以帮助您了解流在 Node.js 中的工作原理。

什么是流?

流是允许您以连续方式从源读取数据或将数据写入目标的对象。它们非常适合逐个处理数据,而不是一次读取或写入整个文件或缓冲区。这在处理大型数据集时特别有用,因为它可以显着减少内存使用量。

关键概念

  • 流动模式:数据自动从源流向目的地。
  • 暂停模式:需要手动从源读取数据。
  • 可读流:可以从中读取数据的流。
  • 可写流:可以写入数据的流。
  • 双工流:既可以读取也可以写入数据的流。
  • 转换流:在读取或写入数据时修改或转换数据的流。

流的类型

  1. 可读流:这些流允许您读取数据。示例包括 fs.createReadStream() 和 http.IncomingMessage.

  2. 可写流:这些流允许您写入数据。示例包括 fs.createWriteStream() 和 http.ServerResponse.

  3. 双工流:这些流可以读取和写入数据。示例包括 TCP 套接字和 net.Duplex.

  4. 转换流:这是一种双工流,可以在读取或写入数据时修改数据。示例包括用于压缩的 zlib.createGzip()。

创建可读流

您可以使用内置的 fs 模块创建可读流来读取文件,或者使用stream.Readable创建自定义可读流。

示例:使用可读流读取文件

const fs = require('fs');

// Create a readable stream
const readableStream = fs.createReadStream('example.txt', { encoding: 'utf8' });

// Handling the 'data' event
readableStream.on('data', (chunk) => {
    console.log('New chunk received:', chunk);
});

// Handling the 'end' event
readableStream.on('end', () => {
    console.log('No more data to read.');
});

示例:自定义可读流

const { Readable } = require('stream');

class MyReadableStream extends Readable {
    constructor(options) {
        super(options);
        this.current = 0;
    }

    _read(size) {
        if (this.current  {
    console.log('Received:', chunk.toString());
});

创建可写流

您可以使用 fs 模块或扩展stream.Writable 类来创建可写流。

示例:使用可写流写入文件

const fs = require('fs');

// Create a writable stream
const writableStream = fs.createWriteStream('output.txt');

// Write data to the stream
writableStream.write('Hello, World!\n');
writableStream.write('Writing to a file using streams.\n');

// End the stream
writableStream.end(() => {
    console.log('Finished writing to file.');
});

示例:自定义可写流

const { Writable } = require('stream');

class MyWritableStream extends Writable {
    _write(chunk, encoding, callback) {
        console.log('Writing:', chunk.toString());
        callback(); // Call when done
    }
}

const myWritableStream = new MyWritableStream();
myWritableStream.write('Hello, World!\n');
myWritableStream.write('Writing to custom writable stream.\n');
myWritableStream.end();

使用双工流

双工流可以同时读取和写入数据。一个常见的用例是 TCP 套接字。

示例:创建双工流

const { Duplex } = require('stream');

class MyDuplexStream extends Duplex {
    _read(size) {
        this.push('Data from duplex stream\n');
        this.push(null); // No more data
    }

    _write(chunk, encoding, callback) {
        console.log('Received:', chunk.toString());
        callback();
    }
}

const myDuplexStream = new MyDuplexStream();
myDuplexStream.on('data', (chunk) => {
    console.log('Reading:', chunk.toString());
});

// Write to the duplex stream
myDuplexStream.write('Hello, Duplex!\n');
myDuplexStream.end();

使用转换流

转换流对于修改流经流的数据非常有用。例如,您可以使用转换流来压缩数据。

示例:创建转换流

const { Transform } = require('stream');

class MyTransformStream extends Transform {
    _transform(chunk, encoding, callback) {
        const upperChunk = chunk.toString().toUpperCase();
        this.push(upperChunk);
        callback();
    }
}

const myTransformStream = new MyTransformStream();
myTransformStream.on('data', (chunk) => {
    console.log('Transformed:', chunk.toString());
});

// Pipe data through the transform stream
process.stdin.pipe(myTransformStream).pipe(process.stdout);

管道流

流的强大功能之一是将它们通过管道连接在一起的能力。管道允许您将可读流连接到可写流,这使得传输数据变得容易。

示例:管道流

const fs = require('fs');

// Create a readable stream
const readableStream = fs.createReadStream('input.txt');

// Create a writable stream
const writableStream = fs.createWriteStream('output.txt');

// Pipe the readable stream to the writable stream
readableStream.pipe(writableStream);

writableStream.on('finish', () => {
    console.log('Data has been written to output.txt');
});

Node.js 中的流事件

1. 可读流事件

可读流发出几个重要事件来帮助您管理数据流:

  • data:当一大块数据可供读取时发出。
  • end:当没有更多数据可供读取时发出。
  • error:读取过程中发生错误时发出。
  • close:当流和任何底层资源(如文件描述符)已关闭时发出。

示例:可读流事件

const fs = require('fs');

const readableStream = fs.createReadStream('example.txt');

readableStream.on('data', (chunk) => {
    console.log('Received chunk:', chunk.toString());
});

readableStream.on('end', () => {
    console.log('No more data to read.');
});

readableStream.on('error', (err) => {
    console.error('Error occurred:', err);
});

readableStream.on('close', () => {
    console.log('Stream closed.');
});

2. 可写流事件

可写流也会发出几个事件:

  • drain:当流已满后准备好接受更多数据时发出。
  • finish:当所有数据都写入流并且调用了 end() 方法时发出。
  • error:写入过程中发生错误时发出。
  • close:当流和任何底层资源关闭时发出。

示例:可写流事件

const fs = require('fs');

const writableStream = fs.createWriteStream('output.txt');

writableStream.on('finish', () => {
    console.log('All data has been written to output.txt');
});

writableStream.on('error', (err) => {
    console.error('Error occurred:', err);
});

// Writing data
writableStream.write('Hello, World!\n');
writableStream.write('Writing to a file using streams.\n');
writableStream.end(); // Call end to finish the writing process

3. 转换流事件

转换流从可读流和可写流继承事件,并且它们发出:

  • data:当转换后的块可供读取时发出。
  • end:当没有更多数据可供转换时发出。
  • error:转换过程中发生错误时发出。
  • finish:当所有数据都已处理并写入时发出。

示例:转换流事件

const { Transform } = require('stream');

class MyTransformStream extends Transform {
    _transform(chunk, encoding, callback) {
        const upperChunk = chunk.toString().toUpperCase();
        this.push(upperChunk);
        callback();
    }
}

const myTransformStream = new MyTransformStream();

myTransformStream.on('data', (chunk) => {
    console.log('Transformed chunk:', chunk.toString());
});

myTransformStream.on('end', () => {
    console.log('No more data to transform.');
});

myTransformStream.on('error', (err) => {
    console.error('Error occurred:', err);
});

// Write data to the transform stream
myTransformStream.write('Hello, World!\n');
myTransformStream.write('Transforming this text.\n');
myTransformStream.end(); // End the stream

活动概要

  • 可读流:数据、结束、错误、关闭
  • 可写流:排出、完成、错误、关闭
  • Transform Streams:从可读流和可写流继承数据、结束、错误、完成

结论

Node.js 中的流提供了一种强大且高效的方式来连续处理数据。它们允许您逐段读取和写入数据,这使得它们对于 I/O 操作和处理大型数据集特别有用。了解如何创建和使用不同类型的流,以及如何处理事件,将帮助您在 Node.js 中构建更高效、可扩展的应用程序。

无论您是创建可读、可写、双工还是转换流,流 API 的灵活性都允许您以最适合您的应用程序需求的方式处理数据。

版本声明 本文转载于:https://dev.to/harshm03/streams-nodejs-2j32?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 为什么Microsoft Visual C ++无法正确实现两台模板的实例?
    为什么Microsoft Visual C ++无法正确实现两台模板的实例?
    The Mystery of "Broken" Two-Phase Template Instantiation in Microsoft Visual C Problem Statement:Users commonly express concerns that Micro...
    编程 发布于2025-03-12
  • UTF-8 vs. Latin-1:字符编码大揭秘!
    UTF-8 vs. Latin-1:字符编码大揭秘!
    [utf-8和latin1 在他们的应用中,出现了一个基本问题:什么辨别特征区分了这两个编码?超出其字符表现能力,UTF-8具有额外的几个优势。从历史上看,MySQL对UTF-8的支持仅限于每个字符的三个字节,这阻碍了基本多语言平面(BMP)之外的字符的表示。但是,随着MySQL 5.5的出现,...
    编程 发布于2025-03-12
  • 大批
    大批
    [2 数组是对象,因此它们在JS中也具有方法。 切片(开始):在新数组中提取部分数组,而无需突变原始数组。 令ARR = ['a','b','c','d','e']; // USECASE:提取直到索引作...
    编程 发布于2025-03-12
  • 如何在Java字符串中有效替换多个子字符串?
    如何在Java字符串中有效替换多个子字符串?
    在java 中有效地替换多个substring,需要在需要替换一个字符串中的多个substring的情况下,很容易求助于重复应用字符串的刺激力量。 However, this can be inefficient for large strings or when working with nu...
    编程 发布于2025-03-12
  • Part SQL注入系列:高级SQL注入技巧详解
    Part SQL注入系列:高级SQL注入技巧详解
    [2 Waymap pentesting工具:单击此处 trixsec github:单击此处 trixsec电报:单击此处 高级SQL注入利用 - 第7部分:尖端技术和预防 欢迎参与我们SQL注入系列的第7部分!该分期付款将攻击者采用的高级SQL注入技术 1。高...
    编程 发布于2025-03-12
  • 为什么PYTZ最初显示出意外的时区偏移?
    为什么PYTZ最初显示出意外的时区偏移?
    与pytz 最初从pytz获得特定的偏移。例如,亚洲/hong_kong最初显示一个七个小时37分钟的偏移: 差异源利用本地化将时区分配给日期,使用了适当的时区名称和偏移量。但是,直接使用DateTime构造器分配时区不允许进行正确的调整。 example pytz.timezone(...
    编程 发布于2025-03-12
  • 如何修复\“常规错误:2006 MySQL Server在插入数据时已经消失\”?
    如何修复\“常规错误:2006 MySQL Server在插入数据时已经消失\”?
    How to Resolve "General error: 2006 MySQL server has gone away" While Inserting RecordsIntroduction:Inserting data into a MySQL database can...
    编程 发布于2025-03-12
  • 我们如何保护有关恶意内容的文件上传?
    我们如何保护有关恶意内容的文件上传?
    对文件上载上传到服务器的安全性问题可以引入重大的安全风险,因为用户可能会提供潜在的恶意内容。了解这些威胁并实施有效的缓解策略对于维持应用程序的安全性至关重要。用户可以将文件名操作以绕过安全措施。避免将其用于关键目的或使用其原始名称保存文件。用户提供的MIME类型可能不可靠。使用服务器端检查确定实际...
    编程 发布于2025-03-12
  • 如何使用JavaScript中的正则表达式从字符串中删除线路断裂?
    如何使用JavaScript中的正则表达式从字符串中删除线路断裂?
    在此代码方案中删除从字符串在JavaScript中解决此问题,根据操作系统的编码,对线断裂的识别不同。 Windows使用“ \ r \ n”序列,Linux采用“ \ n”,Apple系统使用“ \ r。” 来满足各种线路断裂的变化,可以使用以下正则表达式: [&& && &&&&&&&&&&&...
    编程 发布于2025-03-12
  • 为什么使用Firefox后退按钮时JavaScript执行停止?
    为什么使用Firefox后退按钮时JavaScript执行停止?
    导航历史记录问题:JavaScript使用Firefox Back Back 此行为是由浏览器缓存JavaScript资源引起的。要解决此问题并确保在后续页面访问中执行脚本,Firefox用户应设置一个空功能。 警报'); }; alert('inline Alert')...
    编程 发布于2025-03-12
  • 如何使用PHP将斑点(图像)正确插入MySQL?
    如何使用PHP将斑点(图像)正确插入MySQL?
    essue VALUES('$this->image_id','file_get_contents($tmp_image)')";This code builds a string in PHP, but the function call ...
    编程 发布于2025-03-12
  • 我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    将我的加密库从mcrypt升级到openssl 问题:是否可以将我的加密库从McRypt升级到OpenSSL?如果是这样,如何?答案:是的,可以将您的Encryption库从McRypt升级到OpenSSL。可以使用openssl。附加说明: [openssl_decrypt()函数要求iv参...
    编程 发布于2025-03-12
  • 在Java中使用for-to-loop和迭代器进行收集遍历之间是否存在性能差异?
    在Java中使用for-to-loop和迭代器进行收集遍历之间是否存在性能差异?
    For Each Loop vs. Iterator: Efficiency in Collection TraversalIntroductionWhen traversing a collection in Java, the choice arises between using a for-...
    编程 发布于2025-03-12
  • 如何检查对象是否具有Python中的特定属性?
    如何检查对象是否具有Python中的特定属性?
    方法来确定对象属性存在寻求一种方法来验证对象中特定属性的存在。考虑以下示例,其中尝试访问不确定属性会引起错误: >>> a = someClass() >>> A.property Trackback(最近的最新电话): 文件“ ”,第1行, AttributeError: SomeClass...
    编程 发布于2025-03-12
  • Java HashSet/LinkedHashSet随机元素获取方法详解
    Java HashSet/LinkedHashSet随机元素获取方法详解
    在编程中找到一个随机元素,在编程中找到一个随机元素,从集合(例如集合)中选择一个随机元素很有用。 Java提供了多种类型的集合,包括障碍物和链接HASHSET。本文将探讨如何从这些特定集合实现的过程中选择一个随机元素。的java的hashset和linkedhashset a HashSet代表...
    编程 发布于2025-03-12

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3