古詩詞大全網 - 藝術簽名 - 如何利用Node.js實現文件循環覆蓋

如何利用Node.js實現文件循環覆蓋

這次寫Node.js項目的時候用了log模塊,遇到了壹個小問題。

這是壹個定期執行可配置自動化任務的項目,因此輸出信息會不斷增加,這意味著日誌文件會隨著時間的推移不斷增加。如果不控制日誌文件大小,服務器的磁盤遲早會滿。所以有必要限制文件大小。

理想的控制方法是當文件大小超過限制時,清除第壹個記錄的數據。類似於FIFO隊列。

#刪除以前的數據

- 1 xxx

......

100 abc

#在文件末尾追加數據

+ 101 xxxx

log4js的文件滾動

說到日誌,很多Node.js開發者肯定會找log4js。我們來看看log4js是如何處理這個問題的。

Log4js分為很多appenders(可以理解為記錄日誌的介質),文件滾動功能可以通過函數配置。

文件滾動功能有兩種方式:日期和文件大小。

要控制文件大小,當然選擇後者。

為了測試這個函數是否符合我們的要求,寫壹個循環代碼寫壹個日誌。

const log4js = require('log4js ')

//配置log4js

log4js.configure({

附錄:{

壹切:{

類型:“文件”,

文件名:' a.log ',

maxLogSize: 1000,

備份:0

},

},

類別:{

默認值:{

appenders: ['壹切'],

級別:“調試”

}

}

});

const log = log 4js . get logger();

for(設I = 0;我& lt41;i++) {

const str = i.toString()。padStart(6,' 000000 ');

log . debug(str);

}

執行後,會生成兩個文件a.log和a.log.1。

其中a.log.1有20行數據,實際大小是1kb,而a.log只有1行數據。

雖然它確實控制了文件大小,但它會帶來兩個問題:

會生成壹個額外的備份文件,所占用的總磁盤空間將超過文件限制。

日誌文件內容的大小是可變的,因此很可能需要結合備份文件來查詢日誌(例如,上面的情況日誌文件只有1行數據)。

推測log4js的實現邏輯可能如下:

檢查日誌文件是否達到限制大小,如果是,刪除備份文件,否則,繼續寫入日誌文件。

將日誌文件重命名為備份文件。

這顯然不能完全滿足需求。

字符串替換?

如果想在內存中完成循環覆蓋操作,相對簡單,使用string或Buffer即可。

添加字符串/緩沖區的長度,如果超過大小,則截取它。

寫入並覆蓋日誌文件。

但是有壹個很大的問題:占用內存。

例如,如果文件大小限制為1GB,同時寫入10個日誌文件,那麽至少會占用10GB的內存空間!

內存比磁盤空間更有價值,這麽明顯的性能問題顯然不是最好的解決方案。

文件卷

根據要求,實施步驟可分為兩步:

將最新數據追加到文件末尾。(Node.js的fs模塊有相應的函數)

刪除文件開頭超出限制的部分。(Node.js沒有響應函數)

這兩個步驟不分先後,但是Node.js並沒有提供刪除文件開頭的API,只是提供了修改文件指定位置的函數。

既然不能刪除文件開頭的內容,那就換個思路,只保留文件結尾的內容(大小限制內)。

什麽?這不是壹回事嗎?

略有不同~

刪除是對原始文件的操作,而保留內容可以借助臨時文件進行操作。

所以這個想法變成了:

創建壹個臨時文件,其內容來自日誌文件。

將數據添加到臨時文件中。

臨時文件中符合文件大小限制的內容從後向前讀取(以偏移量的形式),並復制到日誌文件中進行覆蓋。

為了不占用額外的磁盤空間,寫操作完成後會刪除臨時文件。

這樣就不會出現log4js這樣不完整的日誌文件,也不會保留額外的臨時文件。但是io的操作會增加~

寫操作可以通過tail命令實現,最終代碼如下:

私有寫(名稱:string,buf?:Buffer | string) {

//將buf追加到tmp文件

const tmpName = name.replace(/(。*\/)(.*$)/, '$1_\.$2\.tmp’);

如果(!existsSync(tmpName)) {

copyFileSync(名稱,tmpName);

}

buf & amp& ampappendFileSync(tmpName,buf);

//如果忙,請等待

如果(this.stream & amp& ampthis.stream.readable) {

this . needupdatelog file[name]= true;

}否則{

嘗試{

execSync(` tail-c $ { limit } $ { tmpName } & gt;$ { name } `);

嘗試{

if(this . needupdatelog file[name]){

this . needupdatelog file[name]= false;

this.write(姓名);

}否則{

existsSync(tmpName)和amp& ampunlink sync(tmpName);

}

} catch (e) {

控制臺.錯誤(e);

}

} catch (e) {

控制臺.錯誤(e);

}

}

}

摘要

完成這壹功能有兩種見解:

量變引起質變。當數據量變大的時候,很多簡單的處理方法就用不上了,比如寫文件。如果直接使用writeFile,會占用大量內存甚至內存可能不夠用。所以需要用合適的方式拆分,在拆分的過程中會遇到各種問題,比如本文中截取文件內容的要求。

學會借錢。君子本性不異,也善於作偽~在單點無法完成操作的時候,可以通過外部條件來實現,比如使用臨時文件來保存本文中的數據內容。

嗯,