您好,登錄后才能下訂單哦!
這篇文章主要介紹了Nodejs如何進行大文件讀寫的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Nodejs如何進行大文件讀寫文章都會有所收獲,下面我們一起來看看吧。
常規的,如果我們要讀取一個比較小的文件,可以直接通過:
const fs = require('fs')
let data = fs.readFileSync("./test.png")
console.log(data,123)
//輸出data =
一般而言,同步的方法不是很推薦,因為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 =
這里通過異步的方法調用不會阻塞主線程,多個文件讀取的IO也可以并行進行等。
常規的文件讀寫,我們會把文件一次性的讀取到內存中,這種方法時間效率和內存效率都很低,時間效率低是指必須要一次性讀取完畢后才能執行后續才做,內存效率低是指必須把這個文件都一次性讀取放入內存中,很占用內存。因此這種情況下,我們一般使用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 =
通過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()
在讀取大文件時,會有讀取文件大小的限制,比如我們現在在讀取一個2.5G的視頻文件:
const fs = require('fs')
const readFileTest = async () => {
let data = await fs.promises.readFile("./video.mp4")
console.log(data)
}
readFileTest()
執行上述的代碼會報錯:
RangeError [ERR_FS_FILE_TOO_LARGE]: File size (2246121911) is greater than 2 GB
我們可能會想到,通過設置option,NODE_OPTIONS='--max-old-space-size=5000',此時5000M>2.5G,但是報錯還是沒有消失,也就是說通過Options無法改變node讀取文件的大小限制。
上述是常規的方式讀取大文件,如果通過Steam的方式讀取還會有文件大小的限制嘛? 比如:
如上方式讀取一個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
此時是因為data的長度超過了最大限制,比如2048M等。因此在用Steam處理的時候,在對讀取結果的保存時,要注意文件的大小,千萬不能超過默認的Buffer的最大值。上述這種情況,我們不用data += chunk將數據全部保存在一個大的data中,我們可以邊讀取邊處理。
createReadStream在讀取文件的過程中,其實也可以分段讀取,這種分段讀取的方法也可以做為大文件讀取的備選項。特別是在并發讀取的時候有一定的優點,可以提升文件讀取和處理的速度。
createReadStream接受第二個參數{start,end}。我們可以通過fs.promises.stat來獲取文件的大小,然后確定分片,最后分片一次讀取,比如:
獲取文件大小
登錄后復制const info = await fs.promises.stat(filepath)
const size = info.size
按照指定的SIZE分片(比如128M一個分片)
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】...
3.實現讀取函數
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', () => {
...
})
}
值得注意的是fs.createReadStream(filepath,{start,end}),start和end是前閉后閉的,比如fs.createReadSteam(filepath,{start:0,end:1023})讀取的是[0,1023]一共1024個bit。
前面將了大文件在nodejs中的讀取,那么在瀏覽器端會讀取大文件會有什么問題嗎?
瀏覽器在本地讀取大文件時,之前有類似FileSaver、StreamSaver等方案,不過在瀏覽器本身添加了File的規范,使得瀏覽器本身就默認和優化了Stream的讀取。我們不需要做額外的工作,相關的工作:github.com/whatwg/fs。不過不同的版本會有兼容性的問題,我們還是可以通過FileSaver等進行兼容。
如果是在瀏覽器中獲取靜態資源大文件,一般情況下只需要通過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也是前閉后閉的。
關于“Nodejs如何進行大文件讀寫”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“Nodejs如何進行大文件讀寫”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。