我试图追加一个字符串到日志文件。但是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。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,所以你的文件将在你的进程结束时结束,你可以避免打开太多文件。

其他回答

对于偶尔的追加,你可以使用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');

但如果重复向同一个文件追加,重用文件句柄会好得多。

使用createWriteStream的代码为每次写入创建一个文件描述符。日志。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。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,所以你的文件将在你的进程结束时结束,你可以避免打开太多文件。

除了appendFile,您还可以在writeFile中传递一个标志来将数据追加到现有文件。

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

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

我包装了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);

            }

        });

    }