Henri Korpela
Henri Korpela

Reputation: 111

NodeJS - How to read multiple files asynchronously and write read contents to one file

I would like to read multiple files asynchronously in NodeJS. It is good to read multiple files at the same time, when the order of reading doesn't matter.

However, I'm trying to write contents of these files together into one file. I can write a file just fine, but how do I make sure that all the files have been read before I write all the contents into that one file?

Upvotes: 1

Views: 2139

Answers (2)

DrakaSAN
DrakaSAN

Reputation: 7853

Using async:

'use strict';

let fs = require('fs'),
    async = require('async'),
    inputs = ['in1', 'in2'],
    output = 'out';

function fuse(inputs, output, callback) {
    async.map(inputs, (path, callback) => {
        fs.readFile(path, callback);
    }, (err, contents) => {
        if(error) {
            callback(error);
        } else {
            fs.writeFile(output, contents.reduce((a, b) => {
                return a + b;
            }), callback);
        }
    });
}

fuse(inputs, output, (error) => {
    if(error) {
        console.log('Error: ' + error);
    } else {
        console.log('OK');
    }
});

EDIT:

Using promises:

'use strict';

const fs = require('fs'),
    inputs = ['in1', 'in2'],
    output = 'out'

// Promisify fs.readFile
function read(file) {
    return new Promise((resolve, reject) => {
        fs.readFile(file, (error, data) => {
            if(error) {
                reject(error);
            } else {
                resolve(data);
            }
        });
    });
}

// Promisify fs.writeFile
function write(file, data) {
    return new Promise((resolve, reject) => {
        fs.writeFile(file, data, (error) => {
            if(error) {
                reject(error);
            } else {
                resolve();
            }
        });
    });
}

Promise.all(inputs.map(read)) // Read all files
    .then((data) => { // data will be a array of the data in the files
        const outData = data.reduce((a, b) => {
            return a + b; // concatenate the data
        })
        return write(output, outData); // write the output
    })
    .then(() => {
        console.log('OK');
    })
    .catch((error) => {
        console.error(error);
    });

(Untested, but general idea's here) As pointed out by libik, fs-promise, util.promisify or bluebird are alternatives to promisify fs.readFile and fs.writeFile.

Upvotes: 3

libik
libik

Reputation: 23029

User Promises by one of the following method

  1. Create promises, each one is resolved when file is read
  2. Use bluebird to create Promise-like methods for fs
  3. Use fs-promise module

Then save all this promises into array and use Promise.all

Other way around can be iterating variable i.e. var filesRead = 0. When file is read, increase this number filesRead++. After this, always check, if you read all the files, if so, you can do the writing

if (filesRead === numberOfFilesToRead){
    //write things
}

Upvotes: 1

Related Questions