gpt4 book ai didi

node.js - 有没有更优雅的方式来读取然后用 Node js流写入*相同的文件*

转载 作者:搜寻专家 更新时间:2023-11-01 00:10:59 25 4
gpt4 key购买 nike

我想读取文件,然后用 through2 更改它,然后写入同一个文件,代码如下:

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

上面的代码可以工作,但我想知道我可以让它更优雅吗?

我也尝试了一些临时库,比如 node-temp

不幸的是,它不能将readStream 和writeStream 写入同一个文件,我打开a issues关于这个。

所以谁知道更好的方法来告诉我,非常感谢。

最佳答案

您可以通过摆脱不必要的依赖关系并为流使用更新的简化构造函数来使代码更优雅。

const fs = require('fs');
const util = require('util');
const stream = require('stream');
const tempWrite = require('temp-write');

const rename = util.promisify(fs.rename);

const goat2llama = async (filePath) => {
const str = fs.createReadStream(filePath, 'utf8')
.pipe(new stream.Transform({
decodeStrings : false,
transform(chunk, encoding, done) {
done(null, chunk.replace(/goat/g, 'llama'));
}
}));
const tempPath = await tempWrite(str);
await rename(tempPath, filePath);
};

测试

AVA测试证明它有效:

import fs from 'fs';
import path from 'path';
import util from 'util';
import test from 'ava';
import mkdirtemp from 'mkdirtemp';
import goat2llama from '.';

const writeFile = util.promisify(fs.writeFile);
const readFile = util.promisify(fs.readFile);

const fixture = async (content) => {
const dir = await mkdirtemp();
const fixturePath = path.join(dir, 'fixture.txt');
await writeFile(fixturePath, content);
return fixturePath;
};

test('goat2llama()', async (t) => {
const filePath = await fixture('I like goats and frogs, but goats the best');
await goat2llama(filePath);
t.is(await readFile(filePath, 'utf8'), 'I like llamas and frogs, but llamas the best');
});

一些关于变化的事情:

  • 实际上不再需要 Through2。过去,正确设置直通或转换流很痛苦,但由于 simplified construction,情况不再如此。 API。
  • 您可能也不需要 graceful-fs。除非您正在进行大量并发磁盘 I/O,否则 EMFILE 通常不是问题,尤其是现在 Node 在文件描述符方面变得更加智能。但该库确实有助于解决由 Windows 上的防病毒软件引起的临时错误,如果这对您来说是个问题的话。
  • 您绝对不需要为此使用 rimraf。你只需要 fs.rename() .它类似于 mv在命令行上,有一些细微差别使其与众不同,但这里的差异并不是特别重要。关键是在您重命名那里的文件后,临时路径上将没有任何内容。
  • 我用了temp-write因为它会为您生成一个安全的随机文件路径并将其放在操作系统临时目录中(不时自动清理),此外它还会为您处理将流转换为 Promise 并处理围绕错误的一些边缘情况。 披露:我在temp-write 中编写了流实现。 :)

总的来说,这是一个不错的改进。但是,仍然存在 boundary problem在评论中讨论。幸运的是,您不是第一个遇到这个问题的人!我不会调用 actual solution特别优雅,如果你自己实现它肯定不会。但是replacestream随时为您提供帮助。

const fs = require('fs');
const util = require('util');
const tempWrite = require('temp-write');
const replaceStream = require('replacestream');

const rename = util.promisify(fs.rename);

const goat2llama = async (filePath) => {
const str = fs.createReadStream(filePath, 'utf8')
.pipe(replaceStream('goat', 'llama'));
const tempPath = await tempWrite(str);
await rename(tempPath, filePath);
};

还有...

I do not like temp files

的确,临时文件通常是坏的。但是,在这种情况下,临时文件由设计良好的库管理,并存储在安全、偏僻的位置。几乎不可能与其他进程发生冲突。即使 rename() 以某种方式失败,文件也会被操作系统清理。

也就是说,您可以使用 fs.readFile() 完全避免使用临时文件。和 fs.writeFile()而不是流媒体。前者还使文本替换变得更加容易,因为您不必担心 block 边界。您必须选择一种方法,但是对于非常大的文件,除了 manually chunking the file 之外,流媒体可能是唯一的选择。 .

关于node.js - 有没有更优雅的方式来读取然后用 Node js流写入*相同的文件*,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46483326/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com