簡體   English   中英

如何附加到節點中的文件?

[英]How to append to a file in Node?

我正在嘗試字符串附加到日志文件中。 但是 writeFile 每次寫入字符串之前都會擦除內容。

fs.writeFile('log.txt', 'Hello Node', function (err) {
  if (err) throw err;
  console.log('It\'s saved!');
}); // => message.txt erased, contains only 'Hello Node'

知道如何以簡單的方式做到這一點嗎?

對於偶爾的追加,您可以使用appendFile ,它會在每次調用時創建一個新的文件句柄:

異步

const fs = require('fs');

fs.appendFile('message.txt', 'data to append', function (err) {
  if (err) throw err;
  console.log('Saved!');
});

同步

const fs = require('fs');

fs.appendFileSync('message.txt', 'data to append');

但是如果你重復追加到同一個文件, 重用文件句柄會好得多。

當您想寫入日志文件時,即將數據附加到文件末尾,切勿使用appendFile appendFile為您添加到文件中的每條數據打開一個文件句柄,一段時間后您會收到一個漂亮的EMFILE錯誤。

我可以補充一點, appendFile並不比WriteStream更容易使用。

appendFile示例:

console.log(new Date().toISOString());
[...Array(10000)].forEach( function (item,index) {
    fs.appendFile("append.txt", index+ "\n", function (err) {
        if (err) console.log(err);
    });
});
console.log(new Date().toISOString());

在我的電腦上最多8000個,你可以將數據附加到文件中,然后你得到這個:

{ Error: EMFILE: too many open files, open 'C:\mypath\append.txt'
    at Error (native)
  errno: -4066,
  code: 'EMFILE',
  syscall: 'open',
  path: 'C:\\mypath\\append.txt' }

此外, appendFile會在啟用時寫入,因此您的日志不會按時間戳寫入。 您可以通過示例進行測試,設置 1000 代替 100000,順序將是隨機的,取決於對文件的訪問。

如果要附加到文件,則必須使用像這樣的可寫流:

var stream = fs.createWriteStream("append.txt", {flags:'a'});
console.log(new Date().toISOString());
[...Array(10000)].forEach( function (item,index) {
    stream.write(index + "\n");
});
console.log(new Date().toISOString());
stream.end();

你在你想要的時候結束它。 您甚至不需要使用stream.end() ,默認選項是AutoClose:true ,因此您的文件將在您的進程結束時結束並且您避免打開太多文件。

您使用 createWriteStream 的代碼為每次寫入創建一個文件描述符。 log.end 更好,因為它要求節點在寫入后立即關閉。

var fs = require('fs');
var logStream = fs.createWriteStream('log.txt', {flags: 'a'});
// use {flags: 'a'} to append and {flags: 'w'} to erase and write a new file
logStream.write('Initial line...');
logStream.end('this is the end line');

除了appendFile ,您還可以在writeFile傳遞一個標志以將數據附加到現有文件。

fs.writeFile('log.txt', 'Hello Node',  {'flag':'a'},  function(err) {
    if (err) {
        return console.error(err);
    }
});

通過傳遞標志'a',數據將被附加到文件的末尾。

您需要打開它,然后寫入。

var fs = require('fs'), str = 'string to append to file';
fs.open('filepath', 'a', 666, function( e, id ) {
  fs.write( id, 'string to append to file', null, 'utf8', function(){
    fs.close(id, function(){
      console.log('file closed');
    });
  });
});

這是一些有助於解釋參數的鏈接

打開

關閉


編輯:此答案不再有效,請查看用於追加的新fs.appendFile方法。

使用a+標志附加創建一個文件(如果不存在):

fs.writeFile('log.txt', 'Hello Node', { flag: "a+" }, (err) => {
  if (err) throw err;
  console.log('The file is created if not existing!!');
}); 

文檔: https : //nodejs.org/api/fs.html#fs_file_system_flags

Node.js 0.8 有fs.appendFile

fs.appendFile('message.txt', 'data to append', (err) => {
  if (err) throw err;
  console.log('The "data to append" was appended to file!');
});

文檔

我的方法比較特殊。 我基本上使用WriteStream解決方案,但實際上沒有通過使用stream.end()來“關閉” fd。 相反,我使用cork / uncork 這獲得了低 RAM 使用率的好處(如果這對任何人都很重要),我相信用於日志記錄/記錄(我的原始用例)更安全。

下面是一個非常簡單的例子。 請注意,我剛剛為展示添加了一個偽for循環——在生產代碼中,我正在等待 websocket 消息。

var stream = fs.createWriteStream("log.txt", {flags:'a'});
for(true) {
  stream.cork();
  stream.write("some content to log");
  process.nextTick(() => stream.uncork());
}

uncork將在下一個滴答中將數據刷新到文件中。

在我的場景中,各種大小的峰值高達每秒約 200 次寫入。 然而,在夜間,每分鍾只需要少量寫入。 即使在高峰時段,該代碼也能非常可靠地工作。

當您需要將某些內容附加到文件時,使用fs.appendFilefsPromises.appendFile是最快和最可靠的選項。

與建議的某些答案相反,如果將文件路徑提供給appendFile函數,它實際上會自行關閉 只有當您傳入通過fs.open()類的文件句柄時,您才需要注意關閉它。

我在一個文件中嘗試了超過 50,000 行。

例子 :

(async () => {
  // using appendFile.
  const fsp = require('fs').promises;
  await fsp.appendFile(
    '/path/to/file', '\r\nHello world.'
  );

  // using apickfs; handles error and edge cases better.
  const apickFileStorage = require('apickfs');
  await apickFileStorage.writeLines(
    '/path/to/directory/', 'filename', 'Hello world.'
  );
})();

在此處輸入圖片說明

參考: https : //github.com/nodejs/node/issues/7560

如果您想要一種簡單無壓力的方式在文件中逐行寫入日志,那么我推薦fs-extra

const os = require('os');
const fs = require('fs-extra');

const file = 'logfile.txt';
const options = {flag: 'a'};

async function writeToFile(text) {
  await fs.outputFile(file, `${text}${os.EOL}`, options);
}

writeToFile('First line');
writeToFile('Second line');
writeToFile('Third line');
writeToFile('Fourth line');
writeToFile('Fifth line');

使用 Node v8.9.4 測試。

fd = fs.openSync(path.join(process.cwd(), 'log.txt'), 'a')
fs.writeSync(fd, 'contents to append')
fs.closeSync(fd)

使用jfile包:

myFile.text+='\nThis is new line to be appended'; //myFile=new JFile(path);

我提供這個建議只是因為對打開標志的控制有時很有用,例如,您可能希望首先將其截斷為現有文件,然后向其附加一系列寫入 - 在這種情況下,在打開文件時使用“w”標志並且在所有寫入完成之前不要關閉它。 當然 appendFile 可能就是你所追求的:-)

  fs.open('log.txt', 'a', function(err, log) {
    if (err) throw err;
    fs.writeFile(log, 'Hello Node', function (err) {
      if (err) throw err;
      fs.close(log, function(err) {
        if (err) throw err;
        console.log('It\'s saved!');
      });
    });
  });

嘗試使用flags: 'a'將數據附加到文件

 var stream = fs.createWriteStream("udp-stream.log", {'flags': 'a'});
  stream.once('open', function(fd) {
    stream.write(msg+"\r\n");
  });

這是一個完整的腳本。 填寫您的文件名並運行它,它應該可以工作! 這是有關腳本背后邏輯的視頻教程

var fs = require('fs');

function ReadAppend(file, appendFile){
  fs.readFile(appendFile, function (err, data) {
    if (err) throw err;
    console.log('File was read');

    fs.appendFile(file, data, function (err) {
      if (err) throw err;
      console.log('The "data to append" was appended to file!');

    });
  });
}
// edit this with your file names
file = 'name_of_main_file.csv';
appendFile = 'name_of_second_file_to_combine.csv';
ReadAppend(file, appendFile);

一個更簡單的方法是

const fs = require('fs');
fs.appendFileSync('file.txt', 'message to append into file');
const inovioLogger = (logger = "") => {
    const log_file = fs.createWriteStream(__dirname + `/../../inoviopay-${new Date().toISOString().slice(0, 10)}.log`, { flags: 'a' });
    const log_stdout = process.stdout;
    log_file.write(logger + '\n');
}

除了denysonique 的 answer 之外,有時在appendFile中使用異步類型的appendFile和其他異步方法,其中 promise 返回而不是回調傳遞。 為此,您需要使用promisify HOF 包裝函數或從 promises 命名空間導入異步函數:

const { appendFile } = require('fs').promises;

await appendFile('path/to/file/to/append', dataToAppend, optionalOptions);

我希望它會有所幫助😉

我將 async fs.appendFile 包裝成一個基於 Promise 的函數。 希望它可以幫助其他人了解這將如何工作。

    append (path, name, data) {

        return new Promise(async (resolve, reject) => {

            try {

                fs.appendFile((path + name), data, async (err) => {

                    if (!err) {

                        return resolve((path + name));

                    } else {

                        return reject(err);

                    }

                });

            } catch (err) {

                return reject(err);

            }

        });

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM