1
\$\begingroup\$

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:

  1. Read File "head.txt" and than write/append its text (not much data) to the file
  2. Text (not much data) generated by node itself -> write/append its text to the file
  3. Text (large data) generated by node itself (loop)
  4. Text (large data) generated by node itself (loop)
  5. 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');
});*/
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Aug 19, 2016 at 10:24
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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.

Check the ES5 code.

./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));
answered Aug 19, 2016 at 11:35
\$\endgroup\$
2
  • \$\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\$ Commented 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\$ Commented Aug 20, 2016 at 0:09

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.