Node.js 是否可以用 node 的 stream 来读并改写最后写入到同一个文件?

dxcqcv · 2017年10月02日 · 最后由 5long 回复于 2017年10月02日 · 6619 次阅读

我现在的做法是多创建一个临时文件,然后删除原文件,重命名临时文件,我想知道有没有更好的办法来实现用 node 流来改写同文件?

代码如下

const rm = require('rimraf')
const through2 = require('through2')
const fs = require('graceful-fs')
// source file path
const replacementPath = `./static/projects/${destPath}/index.html`
// temp file path
const tempfilePath = `./static/projects/${destPath}/tempfile.html`
// read source file then write into temp file
await promiseReplace(replacementPath, tempfilePath)    
// del the source file
rm.sync(replacementPath)
// rename the temp file name to source file name
fs.renameSync(tempfilePath, replacementPath)
// del the temp file
rm.sync(tempfilePath)

// promiseify readStream and writeStream
function promiseReplace (readfile, writefile) {
  return new Promise((res, rej) => {
    fs.createReadStream(readfile)
      .pipe(through2.obj(function (chunk, encoding, done) {
        const replaced = chunk.toString().replace(/id="wrap"/g, 'dududud')
        done(null, replaced)
      }))
      .pipe(fs.createWriteStream(writefile))
      .on('finish', () => {
        console.log('replace done')
        res()
      })
      .on('error', (err) => {
        console.log(err)
        rej(err)
      })
  })
}

简单来说,不建议这么做。

展开来说,把新生成的文件改名覆盖旧文件,这个操作按照 man 3 rename 里的描述是可以做到原子化的。这很可能比你自己实现的原子化方案要靠谱。

具体来说,因为我不知道你要这么做的目的是什么,这个帖子很可能是个 XY Problem:https://ruby-china.org/topics/7154

感谢回复,我想实现的是用户上传一些数据,然后我将得到数据替换原有的 html,生成新的 html 给用户下载

我现在的做法可以实现这个功能,但会需要一个临时文件,所以我想有没有一步生成,不需要临时文件的做法

“生成临时文件”这件事目前有什么问题么?性能?还是硬盘空间?

没有实际的问题,只是多一步操作,我在寻求最佳实践

然后我查 Node.js 的 API 发现有 Transform 和 Duplex 感觉是可以同步读写并更改的,但研究下来发现也是不能对同一个文件流式的进行先读后改最后写入到本文件,那么我现在的做法就是最佳的做法吗?

没有完美的最佳,只有满足限制条件下的最合适。

如果换我来做这个需求,就会直接把生成的结果写入到新文件了事。上传的旧文件扔在那不管,直到硬盘空间吃紧了再考虑清理。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号