如何附加到Node中的文件?

时间:2010-08-11 14:37:32

标签: 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'

任何想法如何以简单的方式做到这一点?

20 个答案:

答案 0 :(得分:657)

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

Asynchronously

const fs = require('fs');

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

Synchronously

const fs = require('fs');

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

但如果你反复追加到同一个文件,那么reuse the file handle要好得多。

答案 1 :(得分:139)

如果要在日志文件中写入,即将数据附加到文件末尾,从不使用appendFileappendFile会打开每个文件的文件句柄您添加到文件中的数据,一段时间后会出现漂亮的EMFILE错误。

我可以补充一点,appendFileWriteStream更容易使用。

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

答案 2 :(得分:109)

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

答案 3 :(得分: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');
    });
  });
});

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

open
write
close


编辑:此答案不再有效,请查看新的fs.appendFile附加方法。

答案 4 :(得分:19)

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

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

通过传递flag' a',数据将附加在文件的末尾。

答案 5 :(得分:13)

节点0.8有fs.appendFile

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

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

答案 6 :(得分:4)

使用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

答案 7 :(得分:4)

我的方法很特别。我基本上使用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次。但是,在夜间,每分钟只需要少量写入。该代码即使在高峰时段也能非常可靠地工作。

答案 8 :(得分:3)

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

答案 9 :(得分:2)

使用jfile包:

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

答案 10 :(得分:1)

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

答案 11 :(得分:1)

如果您希望在文件中逐行轻松地写日志,那么我建议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进行测试。

答案 12 :(得分:1)

更简单的方法是

const fs = require('fs');
fs.appendFileSync('file.txt', 'message to append into file');

答案 13 :(得分:1)

当您需要向文件中添加内容时,使用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.'
  );
})();

enter image description here

参考:https://github.com/nodejs/node/issues/7560
执行示例:https://github.com/apickjs/apickFS/blob/master/writeLines.js

答案 14 :(得分:0)

来自nodejs文档。

  // Creates /tmp/a/apple, regardless of whether `/tmp` and /tmp/a exist.
    fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
      if (err) throw err;
    });

在Windows上,即使在递归的情况下在根目录上使用fs.mkdir()也会导致错误:

    fs.mkdir('/', { recursive: true }, (err) => {
      // => [Error: EPERM: operation not permitted, mkdir 'C:\']
    });

https://nodejs.org/api/fs.html#fs_fs_mkdir_path_options_callback

答案 15 :(得分: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');
}

答案 16 :(得分:0)

除了denysonique's answer之外,有时还使用NodeJS中的appendFile异步类型和其他异步方法,在它们中,promise返回而不是回调传递。为此,您需要使用promisify HOF包装该函数或从promises命名空间导入异步函数:

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

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

希望对您有帮助

答案 17 :(得分:0)

这是一个完整的脚本。填写您的文件名并运行它,它应该工作! 这是脚本背后逻辑的video tutorial

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

答案 18 :(得分:0)

我将异步fs.appendFile包装到基于Promise的函数中。希望它能帮助其他人了解它如何工作。

data02 <- data01 %>% mutate(u = vec_sample(p00, p10, p01, p11))

答案 19 :(得分:0)

尝试使用flags: 'a'将数据追加到文件中

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