在 Node.js 中寫入文件
簡介
使用任何語言進行編程時,經常需要寫入文件。與其他編程語言一樣,帶有 Node.js 的 JavaScript 通過使用處理操作系統文件系統的模塊使處理文件系統變得直觀。
fs 模塊包含操作文件和處理計算平台文件系統的功能。除了讀取和寫入文件之外,您還可以使用該模塊查詢文件統計信息,例如文件大小和計數。
默認情況下,fs
模塊將寫入編碼為“utf8”的文件。 UTF-8 是網頁和其他文檔中常用的編碼。文件編碼是指用於文件內容的字符集。常用的編碼有'utf8'、'ascii'、'binary'、'hex'、'base64'和'utf16le'。
每種字符編碼都有其最有意義的特定優勢和實例。例如,'ascii' 是一種易於讀寫的編碼,但它會從數據流中剝離高位。出於這樣的原因,您需要謹慎選擇字符編碼。
在接下來的幾節中,我們將介紹 fs
的不同方式 允許你寫入文件系統,包括它們的區別和優點。
方法一:使用fs.writeFile
fs
模塊包含一個高級 writeFile
可以將數據異步寫入文件的方法。這意味著,就像 Node.js 中的許多操作一樣,I/O 是非阻塞的,並在操作完成時發出一個事件。我們可以寫一個回調函數在writeFile
時運行 返回。
這是一個將歌詞寫入文件的簡單代碼示例:
// writefile.js
const fs = require('fs');
let lyrics = 'But still I\'m having memories of high speeds when the cops crashed\n' +
'As I laugh, pushin the gas while my Glocks blast\n' +
'We was young and we was dumb but we had heart';
// write to a new file named 2pac.txt
fs.writeFile('2pac.txt', lyrics, (err) => {
// throws an error, you could also catch it here
if (err) throw err;
// success case, the file was saved
console.log('Lyric saved!');
});
我們指定了文件名,以及要寫入的字符,以及方法返回時要運行的回調函數。我們還可以傳遞一個選項對像或字符串來指定要使用的編碼,以及模式和標誌。如果您需要指定字符編碼,那麼這裡是您需要調用該方法的方式:
fs.writeFile('2pac.txt', 'Some other lyric', 'ascii', callback);
請注意,如果文件尚不存在,則調用此方法實際上會創建文件 也一樣,所以您不必為此擔心。
有一個同步方法fs.writeFileSync
您可以使用它來代替 fs.writeFile
.
區別在於 fs.writeFileSync
方法同步執行輸入/輸出操作,在寫入文件時阻塞 Node.js 事件循環。如果您過度執行這些同步寫入,這可能會干擾您的 Node.js 應用程序的性能。在大多數情況下,您應該更喜歡使用異步寫入。
只知道在使用這兩種方法時要小心,因為它們每次都會創建一個新文件或 如果內容已經存在,他們將替換它。如果您只想更新現有文件,則需要使用 appendFile
,我們將在本文後面討論。
方法二:使用fs.write
不像高級的 fs.writeFile
和 fs.writeFileSync
方法,您可以在使用低級 fs.write
寫入 Node.js 中的文件時利用更多控制 方法。 fs.write
方法允許精細控製文件中開始寫入的位置、您可以指定寫入的緩衝區以及要寫入文件的緩衝區的哪一部分。
此外,使用低級寫入功能可以讓您準確了解文件描述符何時釋放並做出相應響應,例如通過在應用程序中發送推送通知。
這是一個示例,我們使用 fs.write
將另外幾行歌詞寫入另一個文件 .
// fs_write.js
const fs = require('fs');
// specify the path to the file, and create a buffer with characters we want to write
let path = 'ghetto_gospel.txt';
let buffer = new Buffer('Those who wish to follow me\nI welcome with my hands\nAnd the red sun sinks at last');
// open the file in writing mode, adding a callback function where we do the actual writing
fs.open(path, 'w', function(err, fd) {
if (err) {
throw 'could not open file: ' + err;
}
// write the contents of the buffer, from position 0 to the end, to the file descriptor returned in opening our file
fs.write(fd, buffer, 0, buffer.length, null, function(err) {
if (err) throw 'error writing file: ' + err;
fs.close(fd, function() {
console.log('wrote the file successfully');
});
});
});
您將要使用 fs.write
在對文件執行細粒度更新時,例如在文件中間的已知位置寫入字節序列。
這些方法適用於文件描述符,您必須使用 fs.open
打開文件進行寫入 然後,最後,用 fs.close
再次關閉它 為了避免內存洩漏。
方法三:使用fs.createWriteStream
當處理特別大的文件,或者來自網絡連接的大文件時,使用流比通過上述寫入整個文件的方法一次性寫入文件更可取。
流一次寫入少量數據。儘管由於數據以塊的形式傳輸而具有速度較慢的缺點,但它在 RAM 性能方面具有優勢。由於整個文件不會一次全部加載到內存中,因此 RAM 使用率較低。
要使用流寫入文件,您需要創建一個新的可寫流。然後,您可以每隔一段時間、一次全部或根據服務器或其他進程的數據可用性將數據寫入流,然後在所有數據包都寫入後永久關閉流。
以下是我們如何執行此操作的代碼示例:
// write_stream.js
const fs = require('fs');
let writeStream = fs.createWriteStream('secret.txt');
// write some data with a base64 encoding
writeStream.write('aef35ghhjdk74hja83ksnfjk888sfsf', 'base64');
// the finish event is emitted when all data has been flushed from the stream
writeStream.on('finish', () => {
console.log('wrote all data to file');
});
// close the stream
writeStream.end();
我們創建了一個可寫流,然後將一些數據寫入該流。我們在發出“完成”事件時包含了一條日誌語句,讓我們知道所有數據都已刷新到底層系統。在這種情況下,這意味著所有數據都已寫入文件系統。
免費電子書:Git Essentials
查看我們的 Git 學習實踐指南,其中包含最佳實踐、行業認可的標準以及隨附的備忘單。停止谷歌搜索 Git 命令並真正學習 它!
鑑於性能優勢,流是一種您將看到在 Node.js 領域中廣泛使用的技術,而不僅僅是用於文件寫入。另一個例子是使用流從網絡連接接收數據。
寫入文件時的錯誤處理
寫入文件時,輸入/輸出期間可能會出現許多不同的錯誤。您的代碼應該解決這些潛在的錯誤。一件簡單的事情是將錯誤作為 Node.js 異常拋出。這會使程序崩潰,因此不建議使用,除非您沒有其他辦法。
例如,如果錯誤只能作為程序員錯誤(也稱為 bug)發生,那麼使程序崩潰可能是最好的響應,因為它會立即提醒程序員錯誤並且不會隱藏錯誤。
當您處理操作錯誤時,例如指定一個不可訪問的路徑,那麼有兩種方法可以採用。一種是調用帶有錯誤的回調函數。然後在回調中包含一些處理錯誤的邏輯,例如記錄錯誤。
或者,您可以在調用可能發生錯誤的程序部分的代碼周圍包含 try/catch 塊。
使用 fs.appendFile 追加到文件
如果我們只想添加到文件的內容,我們可以使用 fs.appendFile
高級方法及其同步對應方法,fs.appendFileSync
.使用 fs.appendFile
如果文件不存在則創建文件,否則追加到文件中。
下面是一個使用 fs.appendFile
的例子 寫入文件。
// append_file.js
const fs = require('fs');
// add a line to a lyric file, using appendFile
fs.appendFile('empirestate.txt', '\nRight there up on Broadway', (err) => {
if (err) throw err;
console.log('The lyrics were updated!');
});
在這裡,我們使用 appendFile
在包含以下歌詞的文件中添加額外的一行:
// empirestate.txt
Empire State of Mind - JAY-Z
I used to cop in Harlem;
hola, my Dominicanos
使用 fs.appendFile
不會覆蓋文件,而是使用我們附加的新數據從結束位置更新它。當您只想更新文件時,這是一個很有用的功能,例如不斷向單個日誌文件添加數據。
所以在運行我們的代碼後,文本文件將如下所示:
// empirestate.txt
Empire State of Mind - JAY-Z
I used to cop in Harlem;
hola, my Dominicanos
Right there up on Broadway
如您所見,舊文本仍然存在,並且我們的新字符串已添加到末尾。
了解更多
想了解更多關於 Node.js 的基礎知識嗎?就個人而言,我建議參加 Wes Bos 的 Learn Node.js 之類的在線課程。您不僅將學習最新的 ES2017 語法,還將構建一個全棧餐廳應用程序。根據我的經驗,構建這樣的真實應用是最快的學習方式。
結論
正如我們所見,在 Node.js 中寫入文件時需要考慮多種方法。最簡單且通常最合適的方法是使用 writeFile
fs
中的方法 模塊。這允許您以異步行為寫入指定的文件路徑,並創建一個新文件或替換該路徑中存在的文件。
如果您正在編寫較大的文件,則應考慮可寫流的分塊寫入功能。這些允許以塊的形式寫入數據緩衝區,而不是一次將數據全部加載到內存中。在這種情況下,使用流可以幫助您獲得更好的性能。
對於特殊情況,可以使用較低級別的fs
fs.write
等實用程序 . fs
模塊支持細粒度的文件寫入操作以滿足您的特定需求。