In my script, node.js reads text files and generates text itself. At the end, I have five "text parts", and want to add them to one file. For this step, it must be considered that the sequence is important, so unfortunately the great async technique of node is obstructive. How would you handle this?
The five text parts consists of:
- Read File "head.txt" and than write/append its text (not much data) to the file
- Text (not much data) generated by node itself -> write/append its text to the file
- Text (large data) generated by node itself (loop)
- Text (large data) generated by node itself (loop)
- Read File "footer.txt" and than write/append its text (normal size) to the file
var fs = require('fs');
var filename = "content.txt";
// (1) Read 'head.txt'
fs.readFileSync('head.txt', 'utf8', function (err, head) {
if (err) {
return console.log('Could not read file.');
}
fs.appendFile(filename, head);
//var writeStream = fs.createWriteStream(filename);
//writeStream.write(head);
});
// (2)
var a = '...';
var b = '...';
var ab = a + b;
//var writeStream = fs.createWriteStream(filename);
//writeStream.write(ab);
//writeStream.end();
fs.appendFileSync(filename, ab);
// (3)
var writeStream = fs.createWriteStream(filename);
for (i = 0; i < xzy.length; i++) {
writeStream.write('...' + xyz[i] + '...');
}
//writeStream.end();
// (4)
var writeStream = fs.createWriteStream(filename);
for (i = 0; i < xyz.length; i++) {
writeStream.write('...' + xyz[i] + '...');
}
//writeStream.end();
// (5) Read 'footer.txt'
fs.readFileSync('footer.txt', 'utf8', function (err, footer) {
if (err) {
return console.log('Could not read file.');
}
var writeStream = fs.createWriteStream(filename);
writeStream.write(footer);
//writeStream.end();
});
/*writeStream.on('finish', function () {
console.log('finish');
});
writeStream.on('close', function () {
console.log('close');
});*/
1 Answer 1
Here we go, I would create some "util" namespace to write some helper code:
./util/index.js
const bPromise = require('bluebird');
const fs = require('fs');
const readFile = bPromise.promisify(fs.readFile);
const appendFile = bPromise.promisify(fs.appendFile);
const createWS = filename => {
var writer = fs.createWriteStream(filename, {defaultEncoding: 'utf8', flags : 'a'});
return {
write : bPromise.promisify(writer.write.bind(writer))
}
}
module.exports = {
readFile,
appendFile,
createWS
}
Thanks to bluebird
we can convert functions with callback functions into functions that returns a resolved or rejected Promise with the result value. So that is what it's done in "./util/index.js".
In your main file:
var { readFile, appendFile, createWS} = require('./util');
var filename = "content.txt";
var writer = createWS(filename);
var xyz = ['x', 'y', 'z'];
// (1) Read 'head.txt'
readFile('head.txt', 'utf8')
.then( head => appendFile(filename, head))
.then( ()=>{
// Head appended
var a = '...';
var b = '...';
var ab = a + b;
return appendFile(filename, ab);
})
.then( ()=>{
// ab appended
//return xyz.reduce((a, b)=> a.then( ()=> writer.write('...' + b + '...') ), Promise.resolve(null) )
// or just
return writer.write(xyz.map(el=>'...' + el + '...').join(''));
})
.then( ()=>{
return writer.write(xyz.map(el=>'...' + el + '...').join(''));
})
.then( ()=>{
return readFile('footer.txt', 'utf8')
.then( footer => writer.write(footer))
})
.then( ()=>{})
.catch(console.error.bind(console));
Now looks very nice and it's clear. There's no need (Like in your code) to execute synchronous functions.
./util/index.js
var bPromise = require('bluebird');
var fs = require('fs');
var readFile = bPromise.promisify(fs.readFile);
var appendFile = bPromise.promisify(fs.appendFile);
var createWS = function createWS(filename) {
var writer = fs.createWriteStream(filename, { defaultEncoding: 'utf8', flags: 'a' });
return {
write: bPromise.promisify(writer.write.bind(writer))
};
};
module.exports = {
readFile: readFile,
appendFile: appendFile,
createWS: createWS
};
index.js
var _require = require('./util');
var readFile = _require.readFile;
var appendFile = _require.appendFile;
var createWS = _require.createWS;
var filename = "content.txt";
var writer = createWS(filename);
var xyz = ['x', 'y', 'z'];
// (1) Read 'head.txt'
readFile('head.txt', 'utf8').then(function (head) {
return appendFile(filename, head);
}).then(function () {
// Head appended
var a = '...';
var b = '...';
var ab = a + b;
return appendFile(filename, ab);
}).then(function () {
// ab appended
//return xyz.reduce((a, b)=> a.then( ()=> writer.write('...' + b + '...') ), Promise.resolve(null) )
// or just
return writer.write(xyz.map(function (el) {
return '...' + el + '...';
}).join(''));
}).then(function () {
return writer.write(xyz.map(function (el) {
return '...' + el + '...';
}).join(''));
}).then(function () {
return readFile('footer.txt', 'utf8').then(function (footer) {
return writer.write(footer);
});
}).then(function () {}).catch(console.error.bind(console));
-
\$\begingroup\$ Works! Just get this:
var { readFile, appendFile, createWS } = require('./util');
SyntaxError: Unexpected token { and when I "splitted" each variable I get createWS is not a function \$\endgroup\$Maximilian Fuchs– Maximilian Fuchs2016年08月19日 21:32:06 +00:00Commented Aug 19, 2016 at 21:32 -
\$\begingroup\$ It's because you have an old version of node, the latest versions comes with new ES6 features like the destructuring declaration in the code. \$\endgroup\$Jose Hermosilla Rodrigo– Jose Hermosilla Rodrigo2016年08月20日 00:09:22 +00:00Commented Aug 20, 2016 at 0:09