我试图将一个字符串追加到日志文件中。然而,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'
有没有简单的方法来做到这一点?
我试图将一个字符串追加到日志文件中。然而,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());
在我的电脑上,文件可以增加数据,这样你就能获得以下结果:
{ 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
在启用时会进行写入,因此您的日志将不会按时间戳编写。您可以尝试使用示例,在100000位置处替换为1000,顺序将是随机的,这取决于对文件的访问。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
,因此当进程结束时文件将自动结束,避免打开过多的文件。
stream.write()
之前执行 stream.end()
,因此我们不应该使用 stream.end()
。另外,正如您提到的,“AutoClose: True” 是默认选项,那么为什么要写一行没有用处的代码呢? - Aashish Kumarfs.appendFile
的结果会导致太多打开的文件,因为您是以异步方式执行它(您只是异步地创建了10000个文件句柄),我相信 appendFileSync
不会有类似的问题,也不会出现使用适当间隔(1秒可能已经足够)或排队的 fs.appendFile
问题。 - apple applefs.appendFileSync
(它可以多次运行而不会出现问题)。如果脚本在使用stream.write
或fs.appendFile
记录日志后崩溃或退出,那么很可能你无法获取已记录的日志(这些日志通常是为了调试崩溃/退出所必需的)。 - Dan你的代码使用createWriteStream为每个写操作创建一个文件描述符。而log.end更好,因为它会要求Node在写操作后立即关闭。
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');
fs.createWriteStream
,那么请使用 flags
参数。如果您使用的是 fs.writeFile
,则需要使用 flag
参数。有关更多信息,请参阅Node.js 文件系统文档。 - Anish Nair使用 a+
标志来追加和创建文件(如果不存在):
fs.writeFile('log.txt', 'Hello Node', { flag: "a+" }, (err) => {
if (err) throw err;
console.log('The file is created if not existing!!');
});
除了appendFile
,你也可以在writeFile
中传递一个标志来将数据追加到现有文件中。
fs.writeFile('log.txt', 'Hello Node', {'flag':'a'}, function(err) {
if (err) {
return console.error(err);
}
});
通过传递标志 'a',数据将被追加到文件末尾。
fs.createWriteStream
,则需要使用 flags
。如果您使用的是 fs.writeFile
,则需要使用 flag
。请参考 Node JS Docs - File System 获取更多信息。 - Anish Nairvar 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方法来进行追加。
我的方法非常特别。我基本上使用WriteStream
解决方案,但不实际通过使用stream.end()
来“关闭”fd。而是使用cork
/uncork
。如果有人关心的话,这样能够低内存占用,并且我认为它更安全地用于日志记录(我的原始用例)。
以下是一个相当简单的示例。请注意,我只添加了一个伪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.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.'
);
})();
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!');
});
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进行测试。
fs.appendFile
后面紧接着使用了process.exit()
,则可能在输出被发送之前就退出了。(使用return
没问题)。 - SilentSteelappendFileSync
。 http://nodejs.org/api/fs.html#fs_fs_appendfilesync_filename_data_options 但是您可能会失去Node的一个重要好处,即异步操作。确保捕获错误。也许在某些操作系统上,如果同时请求文件句柄,您可能会遇到访问被拒绝的情况。对此不太确定。 - SilentSteel