如何附加到Node中的文件?

sup*_*bra 452 node.js

我试图一个字符串附加到日志文件.但是,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'
Run Code Online (Sandbox Code Playgroud)

知道怎么做这个简单的方法吗?

丹尼尔

den*_*que 721

对于偶尔的附加,您可以使用appendFile,每次调用时都会创建一个新的文件句柄:

异步:

const fs = require('fs');

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

同步:

const fs = require('fs');

fs.appendFileSync('message.txt', 'data to append');
Run Code Online (Sandbox Code Playgroud)

但是如果你反复追加到同一个文件,重用文件句柄要好得多.

  • 有谁知道**fs.appendFile**是否保持文件的链接打开所以追加更快?(而不是打开/关闭每个写入)http://nodejs.org/api/fs.html#fs_fs_appendfile_filename_data_encoding_utf8_callback (55认同)
  • 自Node v0.8.0起 (6认同)
  • 如果它很方便:注意这是异步的.这可能导致奇怪的时机和其他事情.例如:如果在`fs.appendFile`之后有`process.exit()`,则可以在发送输出之前退出.(使用`return`很好.) (6认同)
  • @chrisdew感谢您的更新......但是......如果我们不在这里使用已接受的答案,我们该怎么做?你是怎么解决这个困境的? (5认同)
  • 更糟糕的情况是,您可以使用同步版本`appendFileSync`.http://nodejs.org/api/fs.html#fs_fs_appendfilesync_filename_data_options但是你可能会失去Node的一个巨大好处,那就是异步操作.确保你发现错误.也许在某些操作系统上,如果同时请求文件句柄,则可以拒绝访问.不确定. (4认同)
  • @nelsonic根据源代码,没有特别的处理方法. (3认同)
  • 另外,如果文件不存在,则会创建一个文件。文档说:`将数据异步附加到文件,如果文件尚不存在则创建该文件。数据可以是字符串或缓冲区。` (http://nodejs.org/api/fs.html#fs_fs_appendfile_filename_data_options_callback) (2认同)
  • 不要使用`fs.appendFile`。这是一个损坏的 API,它为每次调用使用一个新的文件描述符。在繁忙的服务器上(每秒数百个 `appendFile`),这可能导致所有 1024 个文件描述符都被用完,并且进程无法打开其他文件。 (2认同)
  • @zipzit,您询问chrisdew(我认为现在是fadebee)可以替代fs.appendFile。来自Plaute的答案如何?它说fs.createWriteStream(“ append.txt”,{flags:'a'})。write(myText); (2认同)

Pla*_*ute 176

如果要在日志文件中写入,即将数据附加到文件的末尾,从不使用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());
Run Code Online (Sandbox Code Playgroud)

在我的计算机上最多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' }
Run Code Online (Sandbox Code Playgroud)

此外,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();
Run Code Online (Sandbox Code Playgroud)

你想要的时候结束它.您甚至不需要使用stream.end()默认选项AutoClose:true,因此您的文件将在您的流程结束时结束并且您避免打开太多文件.

  • `由于Javascript的异步性质......什么?Array.forEach是一个同步操作.JS是同步的.它恰好提供了一些管理异步操作的方法,比如Promises和async/await. (10认同)
  • 我猜 `fs.appendFile` 会导致太多打开的文件,因为你以异步方式执行它(你只是异步创建 10000 个文件句柄),我相信 `appendFileSync` 不会有类似的问题,也不是 `fs。 appendFile` 以适当的间隔(1s 可能绰绰有余)或排队。 (4认同)
  • 对于日志,我只使用“fs.appendFileSync”(它可以运行一百万次而不会出现问题)。如果脚本在您使用“stream.write”或“fs.appendFile”记录某些内容后立即崩溃或退出,则很可能您不会写入日志(这很可能需要调试崩溃/退出) (4认同)
  • 谢谢你的答案,但我怀疑是由于Javascript的异步性,它会在`stream.write()`之前执行`stream.end()`,所以我们不应该使用`stream.end() `,同样你提到`AutoClose:True`是一个默认选项,那么为什么要写一条没用的线呢. (3认同)
  • @appleapple但是你每次仍然打开文件。对于日志来说,保持其打开状态更有意义。 (2认同)
  • @RedwolfPrograms 对于繁忙的服务器日志,也许是真的。对于每个执行日志一次,也许不是。无论如何,我只是声明这个答案中的观点(至少是原因)是不正确的。 (2认同)

Fab*_*ari 116

使用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');
Run Code Online (Sandbox Code Playgroud)

  • 缺少第一线!应该是'var fs = require('fs');' (6认同)
  • 或者甚至更好的`var fs = require('graceful-fs')`,它消除了一些已知的问题.有关详细信息,请参阅[docs](https://github.com/isaacs/node-graceful-fs). (5认同)
  • @BennyNeugebauer 使用标志是正确的,你不是。它已经在您将文档链接到 fs.writeFile 之前发布了好几个月,它确实使用了“标志”。但此解决方案使用 fs.createWriteStream 并且参数“标志”是正确的 - https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_options (4认同)
  • 起始行和结束行都在同一行:-p (3认同)
  • **请注意**:如果您使用`fs.createWriteStream`,则使用`flags`.如果你使用`fs.writeFile`那么它就是`flag`.有关更多信息,请参阅[Node JS Docs - 文件系统](https://nodejs.org/api/fs.html). (3认同)
  • 小心!参数不是“ flags”,而是“ flag”(单数):https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback (2认同)

A J*_*A J 23

此外appendFile,您还可以传入一个标志writeFile以将数据附加到现有文件.

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

通过传递标记'a',数据将附加在文件的末尾.

  • **请注意**:如果您使用`fs.createWriteStream`,则使用`flags`.如果你使用`fs.writeFile`那么它就是`flag`.有关更多信息,请参阅[Node JS Docs - 文件系统](https://nodejs.org/api/fs.html). (2认同)

Cor*_*art 19

你需要打开它,然后写入它.

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');
    });
  });
});
Run Code Online (Sandbox Code Playgroud)

以下是一些有助于解释参数的链接

打开

关闭


编辑:这个答案不再有效,请查看新的fs.appendFile方法进行追加.

  • nodejs v0.4.10的答案不再准确. (10认同)

viv*_*wal 18

当您需要将某些内容附加到文件时,使用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.'
  );
})();
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

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


chb*_*own 13

节点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!');
});
Run Code Online (Sandbox Code Playgroud)

文档:http://nodejs.org/docs/latest/api/fs.html#fs_fs_appendfile_filename_data_encoding_utf8_callback


t_d*_*m93 10

使用a+标志附加创建一个文件(如果不存在):

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

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


Tom*_*del 9

我的方法比较特殊。我基本上使用了WriteStream解决方案,但实际上没有通过使用stream.end(). 相反,我使用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());
}
Run Code Online (Sandbox Code Playgroud)

uncork 将在下一个滴答中将数据刷新到文件中。

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


Lui*_* R. 5

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

  • 同意异步,但有时如果您只是编写交互式脚本,同步就可以了。 (8认同)
  • 如果您正在执行单用户命令行应用程序(例如执行某些操作的脚本),那么同步编写绝对可以。这样做事就更快了。如果不是为了这个目的,为什么节点会有同步方法? (8认同)
  • 任何sync()几乎总是一个坏主意,除非你100%确定你绝对需要它。即使这样,你也可能做错了。 (5认同)
  • 并不意味着它是错误的。它只是同步执行。可能不是 Node.js 的最佳实践,但它是受支持的。 (5认同)
  • 我用的是“你做错了”这个短语的口语网络迷因意义。显然支持=P (2认同)

Ben*_*uer 5

如果您想要一种简单无压力的方式在文件中逐行写入日志,那么我推荐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');
Run Code Online (Sandbox Code Playgroud)

使用 Node v8.9.4 测试。