You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何多异步fs.createWriteStream.write()写入同一文件未出现内容混乱?

为什么多异步可写流追加写入同一文件不会导致内容混乱?

我开发了一个Node.js应用,逻辑是遍历1000个URL列表,每个URL获取数据后,调用下面的writeData函数创建新的可写流追加写入文件:

const fs = require("fs");
const writeData = (csvString) => {
  const ws = fs.createWriteStream("output.txt", { flags: "a" });
  ws.write("\n" + csvString, () => {
     console.log("A buffer has been written to the file: ");
     console.log(csvString);
  });
}

module.exports = writeData;

原本预期多次异步调用会导致操作系统层面的并发写入冲突,出现内容混乱截断的情况,但实际每个写入流都能有序追加数据,完全没有错乱。我不关心写入顺序,只疑惑为什么操作系统没出现并发写入的问题?

核心原因:追加模式的原子性保证

当你使用flags: "a"(对应操作系统的O_APPEND标志)打开文件时,操作系统内核会保证追加写入的原子性:

  • 每次写请求的文件偏移量会被自动设置为当前文件末尾,这个「定位+写入」的操作是原子的,不会被其他线程/进程打断。
  • 内核会对并发的追加写请求做同步处理,确保每个写操作的内容完整写入到文件末尾,不会出现两个写请求的内容互相穿插、截断的情况。

另外,你的场景中每次写入的数据量很小(单行csv字符串),Node.js的write方法会直接触发操作系统的write系统调用,小数据量的写请求在O_APPEND模式下,内核的原子性保障会更直接地生效。

关于writeFileSync的误区

你提到用writeFileSync替代异步写入,虽然能避免并发问题,但它是同步阻塞的:每次调用都会卡住Node.js的事件循环,直到写入完成才能处理下一个URL的请求。在遍历1000个URL的场景下,这会导致整体性能急剧下降,显然不是合理的解决方案。

更优的实现方案

频繁创建销毁可写流本身就是低效的,正确的做法是复用单个可写流实例:

const fs = require("fs");
// 创建全局唯一的可写流
const outputStream = fs.createWriteStream("output.txt", { flags: "a" });

const writeData = (csvString) => {
  // 复用同一个流写入数据
  outputStream.write("\n" + csvString, () => {
     console.log("A buffer has been written to the file: ");
     console.log(csvString);
  });
}

// 所有URL处理完成后,手动结束流
const closeStream = () => {
  outputStream.end(() => {
    console.log("所有数据写入完成,流已关闭");
  });
}

module.exports = { writeData, closeStream };

这种方式的好处:

  • 避免了频繁创建销毁流的开销;
  • 所有写操作进入Node.js流的内部队列,由流统一调度写入,控制权在应用层,无需依赖操作系统的同步机制;
  • 可以灵活控制流的关闭时机(所有数据写完后调用end())。

内容的提问来源于stack exchange,提问作者TRose123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 04:57:14