可以将多个fs.write附加到同一个文件以保证执行顺序吗?

时间:2016-10-27 19:33:20

标签: javascript node.js asynchronous fs

假设我们有这样一个程序:

// imagine the string1 to string1000 are very long strings, which will take a while to be written to file system
var arr = ["string1",...,"string1000"]; 
for (let i = 1; i < 1000; i++) {
  fs.write("./same/path/file.txt", arr[i], {flag: "a"}});
}

我的问题是will string1 to string1000 be gurantted to append to the same file in order?

由于fs.write是异步函数,我不确定每次调用fs.write()是如何实际执行的。我假设每个字符串的函数调用应该放在another thread中(如callstack?),一旦完成上一次调用,就可以执行下一个调用。

我不确定我的理解是否准确。

修改1

在评论和答案中,我看到fs.write在不等待callback的情况下多次写入同一文件是不安全的。但是如何写入流?

如果我使用以下代码,它会保证写作顺序吗?

// imagine the string1 to string1000 are very long strings, which will take a while to be written to file system
var arr = ["string1",...,"string1000"]; 
var fileStream = fs.createWriteFileStream("./same/path/file.txt",  { "flags": "a+" });
for (let i = 1; i < 1000; i++) {
  fileStream.write(arr[i]);
}
fileStream.on("error", () => {// do something});
fileStream.on("finish", () => {// do something});
fileStream.end();

任何评论或更正都会有所帮助!谢谢!

3 个答案:

答案 0 :(得分:6)

docs

  

请注意,在不等待回调的情况下,在同一文件上多次使用fs.write是不安全的。对于这种情况,强烈建议使用fs.createWriteStream。

使用流是有效的,因为流固有地保证写入它们的字符串的顺序与从它们读出的顺序相同。

var stream = fs.createWriteStream("./same/path/file.txt");
stream.on('error', console.error);
arr.forEach((str) => { 
  stream.write(str + '\n'); 
});
stream.end();

另一种仍然使用fs.write但确保按顺序发生事情的方法是使用promises来维护顺序逻辑。

function writeToFilePromise(str) {
  return new Promise((resolve, reject) => {
    fs.write("./same/path/file.txt", str, {flag: "a"}}, (err) => {
      if (err) return reject(err);
      resolve();
    });
  });
}

// for every string, 
// write it to the file, 
// then write the next one once that one is finished and so on
arr.reduce((chain, str) => {
  return chain
   .then(() => writeToFilePromise(str));
}, Promise.resolve());

答案 1 :(得分:0)

您可以使用节点的读/写锁定来同步对文件的访问,请参阅以下示例,您可以阅读documentation

var ReadWriteLock = require('rwlock');

var lock = new ReadWriteLock();

lock.writeLock(function (release) {
  fs.appendFile(fileName, addToFile, function(err, data) {
    if(err) 
      console.log("write error); 
    else    
      console.log("write ok");

    release(); // unlock
   });    
});

答案 2 :(得分:0)

我遇到了同样的问题,并为我的项目编写了一个 NPM 包来解决它。它的工作原理是将数据缓冲在一个数组中,然后等待事件循环结束,在对 fs.appendFile 的单个调用中连接和写入数据:

const SeqAppend = require('seqappend');

const writeLog = SeqAppend('log1.txt');

writeLog('Several...');
writeLog('...logged...');
writeLog('.......events');