淺析Nodejs怎麼進行大檔案讀寫
筆者最近在做一些node端的檔案讀寫和分片上傳工作,在這個過程中,發現node讀取的檔案如果超過2G,超過了讀取Blob最大值,會出現讀取異常,此外在node中讀寫檔案也受伺服器RAM的限制等,需要分片讀取,本人記錄一下遇到的問題以及解決問題的經過。 【相關教學推薦:nodejs影片教學】
- node中的檔案讀寫
- node檔案讀寫RAM和Blob大小的限制
- 其他
一、node中的檔案讀寫
1.1 常規檔案讀寫
常規的,如果我們要讀取一個比較小的文件,可以直接通過:
const fs = require('fs') let data = fs.readFileSync("./test.png") console.log(data,123) //输出data = <Buffer 89 50 4e ...>
一般而言,同步的方法不是很推薦,因為js/nodejs是單線程的,同步的方法會阻塞主執行緒。最新版的node直接提供了fs.promise,可以結合async/await直接使用:
const fs = require('fs') const readFileSync = async () => { let data = await fs.promises.readFile("./test.png") console.log(data,123) } readFileSync() //输出data = <Buffer 89 50 4e ...>
這裡透過非同步的方法呼叫不會阻塞主線程,多個檔案讀取的IO也可以並行進行等。
1.2 Stream檔案讀寫
常規的檔案讀寫,我們會把檔案一次的讀取到記憶體中,這個方法時間效率與記憶體效率都很低,時間效率低是指必須要一次讀取完畢後才能執行後續才做,內存效率低是指必須把這個文件都一次性讀取放入內存中,很佔用內存。因此這種情況下,我們一般會使用Stream來進行檔案的讀取:
const fs = require('fs') const readFileTest = () => { var data = '' var rs = fs.createReadStream('./test.png'); rs.on('data', function(chunk) { data += chunk; console.log(chunk) }); rs.on('end',function(){ console.log(data); }); rs.on('error', function(err){ console.log(err.stack); }); } readFileTest() // data = <Buffer 89 50 64 ...>
透過Steam來進行檔案讀寫,可以提高記憶體效率和時間效率。
- 記憶體效率:在處理資料之前,不需要在記憶體中載入大量(或整個)資料
- 時間效率:一旦有了數據,就可以開始處理,這大大減少開始處理資料的時間,而不必等到整個資料載入完畢再處理。
Stream的檔案也支援第二種寫法:
const fs = require('fs') const readFileTest = () => { var data = '' var chunk; var rs = fs.createReadStream('./test.png'); rs.on('readable', function() { while ((chunk=rs.read()) != null) { data += chunk; }}); rs.on('end', function() { console.log(data) }); }; readFileTest()
#二、node檔案讀寫RAM和Blob大小的限制
##2.1 基礎問題
在讀取大檔案時,會有讀取檔案大小的限制,例如我們現在正在讀取一個2.5G的視訊檔案:const fs = require('fs') const readFileTest = async () => { let data = await fs.promises.readFile("./video.mp4") console.log(data) } readFileTest()
- -old-space-size=5000',此時5000M>2.5G,但是報錯還是沒有消失,也就是說透過Options無法改變node讀取檔案的大小限制。
- 如上方式讀取一個2.5G的檔案不會有異常,不過要注意的是這邊有一個報錯:
const fs = require('fs') const readFileTest = () => { var data = '' var rs = fs.createReadStream('./video.mp4'); rs.on('data', function(chunk) { data += chunk; }); rs.on('end',function(){ console.log(data); }); rs.on('error', function(err){ console.log(err.stack); }); } readFileTest()
data += chunk; ^ RangeError: Invalid string length
2.2 分片讀取
createReadStream在讀取檔案的過程中,其實也可以分段讀取,這種分段讀取的方法也可以做為大檔案讀取的備選項。特別是並發讀取的時候有一定的優點,可以提升檔案讀取和處理的速度。
createReadStream接受第二個參數{start,end}。我們可以透過fs.promises.stat來取得檔案的大小,然後確定分片,最後分片一次讀取,例如:取得檔案大小
const info = await fs.promises.stat(filepath) const size = info.size
const SIZE = 128 * 1024 * 1024 let sizeLen = Math.floor(size/SIZE) let total = sizeLen +1 ; for(let i=0;i<=sizeLen;i++){ if(sizeLen ===i){ console.log(i*SIZE,size,total,123) readStremfunc(i*SIZE,size,total) }else{ console.log(i*SIZE,(i+1)*SIZE,total,456) readStremfunc(i*SIZE,(i+1)*SIZE-1,total) } } //分片后【0,128M】,【128M, 256M】...
const readStremfunc = () => { const readStream = fs.createReadStream(filepath,{start:start,end:end}) readStream.setEncoding('binary') let data = '' readStream.on('data', chunk => { data = data + chunk }) readStream.end('data', () => { ... }) }
浏览器在本地读取大文件时,之前有类似FileSaver、StreamSaver等方案,不过在浏览器本身添加了File的规范,使得浏览器本身就默认和优化了Stream的读取。我们不需要做额外的工作,相关的工作:github.com/whatwg/fs。不过不同的版本会有兼容性的问题,我们还是可以通过FileSaver等进行兼容。
3.2 请求静态资源大文件
如果是在浏览器中获取静态资源大文件,一般情况下只需要通过range分配请求即可,一般的CDN加速域名,不管是阿里云还是腾讯云,对于分片请求都支持的很好,我们可以将资源通过cdn加速,然后在浏览器端直接请求cdn加速有的资源。
分片获取cdn静态资源大文件的步骤为,首先通过head请求获取文件大小:
const getHeaderInfo = async (url: string) => { const res: any = await axios.head(url + `?${Math.random()}`); return res?.headers; }; const header = getHeaderInfo(source_url) const size = header['content-length']
我们可以从header中的content-length属性中,获取文件的大小。然后进行分片和分段,最后发起range请求:
const getRangeInfo = async (url: string, start: number, end: number) => { const data = await axios({ method: 'get', url, headers: { range: `bytes=${start}-${end}`, }, responseType: 'blob', }); return data?.data; };
在headers中指定 range: bytes=${start}-${end}
,就可以发起分片请求去获取分段资源,这里的start和end也是前闭后闭的。
更多node相关知识,请访问:nodejs 教程!
以上是淺析Nodejs怎麼進行大檔案讀寫的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

要連接 MySQL 資料庫,需要遵循以下步驟:安裝 mysql2 驅動程式。使用 mysql2.createConnection() 建立連接對象,其中包含主機位址、連接埠、使用者名稱、密碼和資料庫名稱。使用 connection.query() 執行查詢。最後使用 connection.end() 結束連線。

Node.js 中存在以下全域變數:全域物件:global核心模組:process、console、require執行階段環境變數:__dirname、__filename、__line、__column常數:undefined、null、NaN、Infinity、-Infinity

Node.js 安裝目錄中有兩個與 npm 相關的文件:npm 和 npm.cmd,區別如下:擴展名不同:npm 是可執行文件,npm.cmd 是命令視窗快捷方式。 Windows 使用者:npm.cmd 可以在命令提示字元中使用,npm 只能從命令列執行。相容性:npm.cmd 特定於 Windows 系統,npm 跨平台可用。使用建議:Windows 使用者使用 npm.cmd,其他作業系統使用 npm。

PiNetwork節點詳解及安裝指南本文將詳細介紹PiNetwork生態系統中的關鍵角色——Pi節點,並提供安裝和配置的完整步驟。 Pi節點在PiNetwork區塊鏈測試網推出後,成為眾多先鋒積極參與測試的重要環節,為即將到來的主網發布做準備。如果您還不了解PiNetwork,請參考Pi幣是什麼?上市價格多少? Pi用途、挖礦及安全性分析。什麼是PiNetwork? PiNetwork項目始於2019年,擁有其專屬加密貨幣Pi幣。該項目旨在創建一個人人可參與

Node.js 和 Java 的主要差異在於設計和特性:事件驅動與執行緒驅動:Node.js 基於事件驅動,Java 基於執行緒驅動。單執行緒與多執行緒:Node.js 使用單執行緒事件循環,Java 使用多執行緒架構。執行時間環境:Node.js 在 V8 JavaScript 引擎上運行,而 Java 在 JVM 上運行。語法:Node.js 使用 JavaScript 語法,而 Java 使用 Java 語法。用途:Node.js 適用於 I/O 密集型任務,而 Java 適用於大型企業應用程式。

是的,Node.js可用於前端開發,主要優勢包括高效能、豐富的生態系統和跨平台相容性。需要考慮的注意事項有學習曲線、工具支援和社群規模較小。
