」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 流:Node.js

流:Node.js

發佈於2024-11-01
瀏覽:848

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]刪除
最新教學 更多>
  • 了解非同步 JavaScript
    了解非同步 JavaScript
    JavaScript 是一種單執行緒語言,這意味著它一次只能做一件事。然而,Web 應用程式通常需要執行從伺服器取得資料等任務,這可能需要一些時間。如果 JavaScript 必須等待每個任務完成才能繼續,那麼您的 Web 應用程式將會變得緩慢且無回應。這就是非同步(async)JavaScript...
    程式設計 發佈於2024-11-07
  • 您應該避免的錯誤(以及如何修復它們)
    您應該避免的錯誤(以及如何修復它們)
    身為 React 開發人員,很容易陷入某些編碼模式,這些模式一開始看起來很方便,但最終可能會導致問題。在這篇文章中,我們將探討 5 個常見的 React 錯誤,並討論如何避免它們,確保您的程式碼保持高效、可維護和可擴展。 1. 濫用關鍵道具 錯誤: {myList.map((ite...
    程式設計 發佈於2024-11-07
  • 如何在 PHP 中存取 JavaScript 變數值?
    如何在 PHP 中存取 JavaScript 變數值?
    在PHP 中使用JavaScript 變數值使用同時涉及JavaScript 和PHP 的Web 應用程式時,通常需要在兩者之間交換資料兩種語言。然而,由於語言的執行環境不同,直接在 PHP 中存取 JavaScript 變數是不可能的。 PHP 在伺服器端執行,而 JavaScript 在客戶端運...
    程式設計 發佈於2024-11-07
  • Popver API VS 對話方塊模態:相同但不同
    Popver API VS 對話方塊模態:相同但不同
    我在閱讀一些科技新聞部落格時偶然發現標題 Popover API 登陸 Baseline。我很困惑,在我最近深入前端開發期間,我最近很難習慣在 HTML 中使用 Elements。在瀏覽部落格時,我一直對到目前為止我如何使用該元素感到困惑。 長話短說 選擇: 需要使用者焦點的模態彈...
    程式設計 發佈於2024-11-07
  • Go中不嵌入結構體可以實現方法繼承嗎?
    Go中不嵌入結構體可以實現方法繼承嗎?
    嵌入式結構:方法繼承的探索理解Go 中的方法繼承 In在Go 中,將方法從一種類型繼承到另一種類型的能力主要是透過嵌入結構來實現的。此技術涉及將一個結構嵌入另一個結構,允許外部結構存取和利用嵌入結構的方法。 嵌入結構的範例考慮以下內容程式碼片段:type Properties map[string]...
    程式設計 發佈於2024-11-07
  • 如何在 PHP 中的 Foreach 迴圈中檢索數組鍵
    如何在 PHP 中的 Foreach 迴圈中檢索數組鍵
    在Foreach 循環期間檢索數組鍵:PHP在PHP 中使用數組時,通常需要檢索其中的鍵和值foreach 循環。 key() 函數提供了一種在迭代期間存取當前鍵的便捷方法。但是,在某些情況下,它可能不會產生所需的結果。 考慮以下程式碼,其目的是從範例陣列產生 HTML 表:foreach($sam...
    程式設計 發佈於2024-11-07
  • 在 JavaScript 中建立物件的方法
    在 JavaScript 中建立物件的方法
    介紹 在 JavaScript 中建立物件的方法有很多種。 對象字面量 Object() 建構子 Object.create() 建構子 ES6 類 對象字面量 這可能是在 JavaScript 中建立物件最快、最簡單的方法。這也稱為物件初始值設定項,是一個由零對...
    程式設計 發佈於2024-11-07
  • 如何在 JavaScript 中擴充自訂異常的錯誤物件?
    如何在 JavaScript 中擴充自訂異常的錯誤物件?
    擴充JavaScript 中的錯誤物件在JavaScript 中拋出例外時,可能想要擴充內建Error 物件以建立自訂錯誤類型。這允許更具體和資訊豐富的異常處理。 在JavaScript 中,繼承不是透過子類化與Python 不同,在Python 中,異常通常是從Exception 基類進行子類化的...
    程式設計 發佈於2024-11-07
  • MySQL如何保證並發操作時資料的完整性?
    MySQL如何保證並發操作時資料的完整性?
    MySQL 並發:確保資料完整性如果您的MySQL 資料庫使用InnoDB 儲存引擎,您可能會擔心在執行過程中潛在的並發問題。同時記錄更新或插入。本文探討了 MySQL 如何處理並發以及是否需要在應用程式中加入額外的處理。 MySQL 的同時處理MySQL 採用原子性,這意味著單獨的 SQL 語句是...
    程式設計 發佈於2024-11-07
  • 如何使用 Go 在 SQL 查詢中有效連接字串和值?
    如何使用 Go 在 SQL 查詢中有效連接字串和值?
    在Go 中有效地製作SQL 查詢在Go 中將字串與文字SQL 查詢中的值連接起來可能有點棘手。與 Python 不同,Go 的字串格式化語法行為不同,導致常見錯誤,如此處遇到的錯誤。 元組語法錯誤初始程式碼片段嘗試使用 Python -style 元組,Go 中不支援。這會導致語法錯誤:query ...
    程式設計 發佈於2024-11-07
  • 為什麼 json_encode() 無法使用 Latin1 編碼對 MySQL 資料庫中的重音字元進行編碼?
    為什麼 json_encode() 無法使用 Latin1 編碼對 MySQL 資料庫中的重音字元進行編碼?
    MySQL 中UTF-8 字元的JSON 編碼難題當嘗試使用latin1_swedish_ci 編碼從資料庫中檢索重音字元並使用json_encode() 將它們編碼為JSON 時,結果可能出乎意料。預期結果(例如“Abord â Plouffe”)會轉換為“null”,從而使編碼的 JSON 無效...
    程式設計 發佈於2024-11-07
  • 如何在 MySQL 中將行轉置為列:綜合指南
    如何在 MySQL 中將行轉置為列:綜合指南
    在MySQL 中將行轉換為列在MySQL 中將行轉換為列在MySQL 查詢中將行轉換為列需要在應用程式中執行複雜的查詢或手動操作。 GROUP_CONCAT 解雖然 GROUP_CONCAT 可以將行轉換為單列,但它不提供整個結果集所需的轉置。 手動查詢方法對於更複雜的轉置,需要細緻的查詢,從原始行...
    程式設計 發佈於2024-11-07
  • 如何解決iOS後台模式下未收到GCM通知的問題
    如何解決iOS後台模式下未收到GCM通知的問題
    當應用程式在iOS 上處於後台模式時未收到GCM 通知當iOS 在後台收到通知但不處理時,會出現此問題它們在使用者介面中。若要解決此問題,請確保您的應用程式:啟用後台推播通知:檢查您的應用程式是否已要求並取得在背景接收推播通知的權限。 設定徽章應用程式圖示:驗證是否在應用程式的「設定」>「通知」部分...
    程式設計 發佈於2024-11-07
  • 為什麼在 Windows 7 中使用 CLASSPATH 時出現 ClassNotFoundException?
    為什麼在 Windows 7 中使用 CLASSPATH 時出現 ClassNotFoundException?
    儘管使用CLASSPATH 環境變數仍解決java.lang.ClassNotFoundException在Windows 7 中嘗試使用Java 連線至MySQL 資料庫時,設定CLASSPATH 環境變數以包含JDBC 驅動程式jar 檔案的路徑似乎無法解決java.lang.ClassNotF...
    程式設計 發佈於2024-11-07
  • 開發人員需要了解免費外匯 API
    開發人員需要了解免費外匯 API
    如果您是一名开发人员,您一定正在寻找可以帮助您更轻松地工作的工具,对吗?免费的外汇 API 就是其中之一!它使您无需支付任何费用即可获取外汇汇率。但是,许多开发人员对这些 API 不太了解。因此,本文旨在解释什么是免费外汇 API、它为何有用以及如何为您的项目选择一个 API。 什么是免费外汇 A...
    程式設計 發佈於2024-11-07

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3