如何在 Node 中追加到文件?

问题描述 投票:0回答:18

我正在尝试将字符串追加到日志文件中。然而 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'

知道如何以简单的方式做到这一点吗?

javascript node.js fs appendfile
18个回答
1168
投票

对于偶尔的追加,您可以使用

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');

但是,如果您重复追加到同一个文件,最好重用文件句柄


411
投票

当您想要写入日志文件时,即将数据附加到文件末尾,从不使用

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
,因此您的文件将在进程结束时结束,并且避免打开太多文件。


164
投票

使用 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');

47
投票

使用

a+
标志来 appendcreate 文件(如果不存在):

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


38
投票

除了

appendFile
之外,您还可以在
writeFile
中传递标志以将数据附加到现有文件。

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

通过传递标志'a',数据将被附加到文件末尾。


27
投票

您需要打开它,然后写入内容。

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 追加方法。


19
投票

当您需要向文件追加内容时,使用

fs.appendFile
fsPromises.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.'
  );
})();

enter image description here

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


17
投票

我的做法比较特别。我基本上使用

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
将在下一个tick中将数据刷新到文件中。

在我的场景中,各种大小的写入峰值可达每秒约 200 次。然而,在夜间,每分钟只需要少量写入。即使在高峰时段,该代码也运行得非常可靠。


14
投票

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!');
});

文档


7
投票

如果您想要一种简单、无压力的方式在文件中逐行写入日志,那么我推荐 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 进行测试。


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

3
投票

我提供此建议只是因为对打开标志的控制有时很有用,例如,您可能想先将其截断为现有文件,然后然后向其追加一系列写入操作 - 在这种情况下,请使用 '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!');
      });
    });
  });

3
投票

尝试使用

flags: 'a'
将数据追加到文件中

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

2
投票

使用 jfile 包:

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

0
投票

这是一个完整的脚本。填写您的文件名并运行它,它应该可以工作! 这是关于脚本背后逻辑的视频教程

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);

0
投票
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');
}

0
投票

除了 denysonique 的回答之外,有时还会使用异步类型的

appendFile
和 NodeJS 中的其他异步方法,其中 Promise 返回而不是回调传递。为此,您需要使用
promisify
HOF 包装函数或从 Promise 命名空间导入异步函数:

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

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

希望对你有帮助😉


0
投票

我将 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);

            }

        });

    }
© www.soinside.com 2019 - 2024. All rights reserved.