Node.js преобразует поток файлов и записывает в тот же файл, в результате получается пустой файл
Я пытаюсь изменить некоторые файлы, используя потоки файлов узла и пользовательские функции преобразования. Это функция преобразования:
const TransformStream = function() {
Transform.call(this, {objectMode: true});
};
util.inherits(TransformStream, Transform);
TransformStream.prototype._transform = function(chunk, encoding, callback) {
let line = chunk.toString()
if (!this.findLinesMode && lineStartRe.test(line)) {
this.findLinesMode = true
this.lines = []
}
if (this.findLinesMode) {
this.lines.push(line)
}
if (this.findLinesMode && lineEndRe.test(line)) {
this.findLinesMode = false
line = this.lines.join('').replace(re, (str, match) => match.trim())
}
if (!this.findLinesMode) {
this.push(line + '\n')
}
callback()
};
И я попытался использовать его в следующем коде:
byline(fs.createReadStream(filePath, {encoding: 'utf8'}))
.pipe(new TransformStream())
.pipe(fs.createWriteStream(filePath))
Тем не менее, файл заканчивается пустым.
Я уверен, что код преобразователя работает, как и ожидалось, потому что я попытался передать его process.stdout
и вывод именно так, как я хочу.
У меня вопрос: что я делаю не так и что я могу попытаться исправить?
2 ответа
Это не проблема с вашим кодом преобразователя, а проблема в том, что вы открываете файл для записи, который вы перезаписываете, вероятно, еще до того, как что-то прочитаете из него.
Это было бы то же самое в оболочке. Если вы запускаете:
cat < file.txt > file.txt
или же:
tr a-z A-Z < x.txt > x.txt
это приведет к тому, что файл станет пустым.
Вы должны передать во временный файл, а затем заменить старый файл новым. Или, в качестве альтернативы, переименуйте старое в другое временное имя, откройте новый файл под правильным именем и передайте переименованный файл старому файлу, выполняя ваши преобразования в пути.
Убедитесь, что вы используете безопасный способ сделать имя временного файла. Вы можете использовать такие модули, как:
Используя предложение @rsp, мы можем использоватьtmp
package из NPM, чтобы создать временный файл и записать в него запись после преобразования. Следующий шаг — скопировать этот файл в исходный файл.
const fs = require("fs");
const {Transform} = require("stream");
const tmp = require("tmp")
const readStream = fs.createReadStream(this.databasePath);
const tmpFile = tmp.fileSync({'postfix' : '.json'});
const writeStream = fs.createWriteStream(tmpFile.name);
const filePath = this.databasePath;
try{
readStream.pipe(
new Transform({
transform(chunk, encoding, callback){
let fileData = JSON.parse(chunk);
fileData.data = fileData.data.map((_doc, _index) => {
let updatedDoc = _doc;
if(_doc._id===_id){
updatedDoc = {..._doc,[ _field] : _value};
}
return updatedDoc;
});
callback(null,JSON.stringify(fileData));
}
})
).pipe(writeStream).on('finish', () =>{
return fs.copyFile(tmpFile.name, filePath, (err) =>{
if(err) {
throw err;
}
})
});
this.data = this.updatedData;
}
catch(error){
// undo the changes in the local copy
this.updatedData = this.data;
return this._handleData(error, null);
}
Это пример, показывающий, как использовать пакет tmp для обновления исходного файла с использованием временной копии.