node.js實現(xiàn)逐行讀取文件內(nèi)容的代碼
Node.js可以同步或異步的方式逐行讀取文件內(nèi)容。其中,異步方式可以讀取大型文件而不需要同時加載文件所有內(nèi)容。
本文介紹4種逐行讀取文件內(nèi)容的Node.js操作,并做了性能測試,優(yōu)劣評判。
準(zhǔn)備
在寫代碼之前,要做以下準(zhǔn)備:
- 安裝 Node.js 10+
- 熟悉NPM
- 了解NodeJs事件驅(qū)動和非阻塞機(jī)制
- 了解stream 流數(shù)據(jù)
測試文件
故意選了一個相對較大(90MB)、行數(shù)較多(798148 行)的 broadband.sql 文件,以便做性能測試。
同步方式
const fs = require('fs'); const allFileContents = fs.readFileSync('broadband.sql', 'utf-8'); allFileContents.split(/\r?\n/).forEach(line => { console.log(`Line from file: ${line}`); }); const used = process.memoryUsage().heapUsed / 1024 / 1024; console.log(`The script uses approximately ${Math.round(used * 100) / 100} MB`);
把文件讀取內(nèi)存之中,按行分割,循環(huán)打印各行。
執(zhí)行腳本
node readfilesync.js
內(nèi)存消耗200MB+,費時2-3分鐘。
The script uses approximately 238.74 MB
如果文件大小1GB,不推薦使用同步讀取的方式,內(nèi)存消耗太大。
接下來,我們將研究一種更高效的異步方式,通過 readline 和另一個原生 Node.js 模塊的 stream 逐行讀取文件。
Readline
Readline 是Node.js原生模塊,無需安裝。它提供了用于從可讀流(例如 process.stdin)每次一行地讀取數(shù)據(jù)的接口。每當(dāng) input 流接收到行尾輸入(\n、\r 或 \r\n)時,則會觸發(fā) ‘line’ 事件。
下面是帶有可讀流的 readline 的代碼示例:
const events = require('events'); const fs = require('fs'); const readline = require('readline'); (async function processLineByLine() { try { const rl = readline.createInterface({ input: fs.createReadStream('broadband.sql'), crlfDelay: Infinity }); rl.on('line', (line) => { console.log(`Line from file: ${line}`); }); await events.once(rl, 'close'); console.log('Reading file line by line with readline done.'); const used = process.memoryUsage().heapUsed / 1024 / 1024; console.log(`The script uses approximately ${Math.round(used * 100) / 100} MB`); } catch (err) { console.error(err); } })();
理解一下以上代碼:
首先引入Node.js的3個原生模塊 events, fs, 和 readline。
•定義了一個名為 processLineByLine 的異步函數(shù),它為 readline 創(chuàng)建了一個接口,其中輸入是我們傳遞 90 MB 測試文件的讀取流。
•設(shè)置為無窮大的 crlfDelay 。crlfDelay 如果 \r 和 \n 之間的延遲超過 crlfDelay 毫秒,則 \r 和 \n 都將被視為單獨的行尾輸入。 crlfDelay 將被強(qiáng)制為不小于 100 的數(shù)字。 它可以設(shè)置為 Infinity,在這種情況下,\r 后跟 \n 將始終被視為單個換行符(這對于具有 \r\n 行分隔符的文件讀取可能是合理的)。 默認(rèn)值: 100。
•在可讀流交互時,每讀取一行,就會觸發(fā) rl.on 讀行函數(shù)。此時,就可以從流中讀取的行的內(nèi)容。
•然后我們用 events.once 監(jiān)聽 readline 關(guān)閉事件,它創(chuàng)建一個 Promise,該 Promise 將使用一個包含所有發(fā)送給給定事件的參數(shù)的數(shù)組來解析。在這種情況下,它將是一個空數(shù)組。
•最后記錄內(nèi)存使用情況
執(zhí)行腳本
node readline.js
結(jié)果耗時很長(5-8分鐘左右),內(nèi)容占用率較低。
The script uses approximately 5.77 MB
N-readlines
N-readline 是一個 NPM 模塊,它可以逐行讀取文件,而不會將整個文件緩沖在內(nèi)存中。它在不使用流的情況下,通過使用 Buffer 和本機(jī)文件系統(tǒng)模塊以塊的形式讀取文件的內(nèi)容。即使它以同步方式工作,它也不會將整個文件加載到內(nèi)存中。
首先,安裝 n-readlines 模塊
npm i --save n-readlines:
通過N-readlines逐行讀取文件如下:
const nReadlines = require('n-readlines'); const broadbandLines = new nReadlines('broadband.sql'); let line; let lineNumber = 1; while (line = broadbandLines.next()) { console.log(`Line ${lineNumber} has: ${line.toString('ascii')}`); lineNumber++; } console.log('end of file.'); const used = process.memoryUsage().heapUsed / 1024 / 1024; console.log(`The script uses approximately ${Math.round(used * 100) / 100} MB`);
以上代碼相對較為簡節(jié)。
•首先,引入 N-readlines 模塊•創(chuàng)建一個讀取文件的實例。默認(rèn)參數(shù)是文件名, readChunk 和 newLineCharacter 可以作為第二個參數(shù)傳入 。這里只使用文件名參數(shù)。•定義兩個變量 line 和 lineNumber 。 Line 變量將保存文件每一行的字符串,而 lineNumber 將保存從 1 到文件行數(shù)的行號。•最后,文件讀取結(jié)束之后打印出大概的內(nèi)存使用情況。
執(zhí)行腳本
node n-readlines.js
耗時巨長,內(nèi)存消耗小。
The script uses approximately 4.09 MB
Line reader
Line reader 模塊將自己定義為“支持用戶定義的行分隔符的異步、緩沖、逐行文件/流讀取器”。它提供 eachLine 函數(shù)讀取給定文件的每一行。eachLine的回調(diào)函數(shù)中的last變量可用于確定是否已到達(dá)文件的最后一行。
下面是使用 line reader 讀取我們相對較大的 90 MB SQL 文件的工作示例,我們使用 npm i –save line-reader 安裝它。完整代碼如下:
const lineReader = require('line-reader'); lineReader.eachLine('broadband.sql', function(line, last) { console.log(`Line from file: ${line}`); if(last) { console.log('Last line printed.'); const used = process.memoryUsage().heapUsed / 1024 / 1024; console.log(`The script uses approximately ${Math.round(used * 100) / 100} MB`); } });
代碼解析
•首先,引入 line-reader 模塊
•調(diào)用 eachLine 函數(shù),將文件名(或文件路徑)作為第一個參數(shù)傳遞。
•第2個參數(shù)是一個回調(diào)函數(shù),包含 line 和 last 變量。
•在回調(diào)函數(shù)中打印行內(nèi)容。
•最后,如果我們發(fā)現(xiàn)最后一個變量為真,這表明我們已經(jīng)到達(dá)文件的末尾,打印出用于逐行讀取文件的內(nèi)存消耗。
執(zhí)行腳本
node line-reader.js
時長感人,內(nèi)存占用極少。
The script uses approximately 2.48 MB
其它方式
還有其他選項可以使用 Node.js 逐行讀取文件。有一個非常流行的 NPM 模塊叫做 readline ,但由于與原生 Node.js 模塊的名稱沖突,現(xiàn)在它已重命名為 Line By LIne。它的工作方式與本機(jī) readline 模塊非常相似
其他不太流行但可用的模塊有 readline 和 readlines-ng,它們在每周僅被下載了大約 3 次。
使用JavaScript 數(shù)組函數(shù),可以非常方便對于文件內(nèi)容的進(jìn)一步處理。
快速比較
在 NPM Trends 上對這四個 NPM 模塊的快速比較顯示,N-readlines 是下載量最大的模塊,上周下載量為 56K。第二個是上周下載量為 46K 的 line-reader,但請記住 line-reader 最近一次更新是在 6 年前。以下是過去 1 年的下載快照:
推薦優(yōu)先選擇流行的類庫,最近更新的類庫是n-readlines,更新時間為1年前。
readline 和 readlines ng 的下載量約為每周 3 次,而 line reader 和 n-readlines 的下載量分別為 46K 和 56K。
在內(nèi)存和 CPU 使用率方面,除了第一個 fs.readfilesync 之外的所有其他基于流或回調(diào)的方法,都消耗內(nèi)存低于 10 MB ,并在 10 秒前完成,CPU 使用率為 70-94%。對于 90 MB 的文件,讀取文件同步消耗了 225 MB 的內(nèi)存。(實測,時間的消耗長達(dá)10幾分鐘的都有,可能是我電腦配置太低了)
總結(jié)
我們研究了如何在 Node.js 中逐行讀取文件。這是個小問題,在 Node.js 中可以使用多種方法來解決。
我們還分析了 3 種方法中每種方法的內(nèi)存使用情況和時間。
最后,我們快速比較了各類庫的受歡迎程度,希望能對你有幫助。
補(bǔ)充
在此之前先介紹一個逐行讀取文件內(nèi)容NPM:https://github.com/nickewing/line-reader,需要的朋友可以看看。
直接上代碼:
function readLines(input, func) { var remaining = ''; input.on('data', function(data) { remaining += data; var index = remaining.indexOf('\n'); while (index > -1) { var line = remaining.substring(0, index); remaining = remaining.substring(index + 1); func(line); index = remaining.indexOf('\n'); } }); input.on('end', function() { if (remaining.length > 0) { func(remaining); } }); } function func(data) { container.push(data); } var input = fs.createReadStream(__dirname + '/ip_arr.txt'); readLines(input, func);
到此這篇關(guān)于node.js實現(xiàn)逐行讀取文件內(nèi)容的代碼的文章就介紹到這了,更多相關(guān)node.js逐行讀取文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- node.js?readline和line-reader逐行讀取文件方法
- node.js讀取命令行參數(shù)詳解
- node.js通過url讀取文件
- node.js使用fs讀取文件出錯的解決方案
- Node.js fs模塊(文件模塊)創(chuàng)建、刪除目錄(文件)讀取寫入文件流的方法
- Node.js中讀取TXT文件內(nèi)容fs.readFile()用法
- node.js讀取Excel數(shù)據(jù)(下載圖片)的方法示例
- Node.js readline 逐行讀取、寫入文件內(nèi)容的示例
- 教你用十行node.js代碼讀取docx的文本
- Node.js讀取文件內(nèi)容示例
- node.js讀取文件到字符串的方法
- node.js生成與讀取csv文件方法詳解
相關(guān)文章
詳解express使用vue-router的history踩坑
這篇文章主要介紹了express 使用 vue-router 的 history 踩坑,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06node.js同步/異步文件讀寫-fs,Stream文件流操作實例詳解
這篇文章主要介紹了node.js同步/異步文件讀寫-fs,Stream文件流操作,結(jié)合實例形式詳細(xì)分析了node.js針對文件的同步/異步讀寫與文件流相關(guān)操作技巧,需要的朋友可以參考下2023-06-06使用nodejs+express實現(xiàn)簡單的文件上傳功能
這篇文章主要介紹了使用nodejs+express完成簡單的文件上傳功能,需要的朋友可以參考下2017-12-12用C/C++來實現(xiàn) Node.js 的模塊(二)
上篇文章的主要內(nèi)容講訴了用C/C++來實現(xiàn) Node.js 的模塊,本文更深一步繼續(xù)探討這個問題,有需要的朋友可以參考下2014-09-09