27

What I want to do is read a file and then be able to perform other operations with that information as I write the file. For example:

read file write file and at the same time perform MD5 hash, digital signing etc.

I could use fs.readfile and fs.writefile as one operation and just copy the file from the web server to my computer, but I don't think I could still do these same operations. Anyway, skipping the in between stuff. How do I use fs.readfile and writefile to create two separate functions to copy a file? Here is what I have been working on, and yes I've read these forums extensively in search of an answer.

var fs = require('fs');



function getData(srcPath) { 
fs.readFile(srcPath, 'utf8', function (err, data) {
        if (err) throw err;
        return data;
        }
    );
}


function writeData(savPath, srcPath) {
        fs.writeFile (savPath, (getData(srcPath)), function(err) {
        if (err) throw err;
            console.log('complete');
        }
    );
}
//getData ('./test/test.txt');
writeData ('./test/test1.txt','./test/test.txt');

I want to be able to download files of any type and just make raw copies, with md5 hash etc attached to a JSON file. That will probably be a question for later though.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Todd Keck
  • 273
  • 1
  • 3
  • 4
  • getData does nothing in your code. you need to to call writeFile in the callback of readFile. if you want to git-r-dun, there's always fs.readFileSync(), which works as you probably expect it to. – dandavis Jul 15 '13 at 01:22

3 Answers3

27

As suggested by dandavis in his comment, readFile does nothing because it is an asynchronous call. Check out this answer for additional information on what that means.

In short, an async call will never wait for the result to return. In your example, getData does not wait for readFile() to return the result you want, but will finish right away. Async calls are usually handled by passing callbacks, which is the last parameter to readFile and writeFile.

In any case, there are two ways to do this:

1.Do it asynchronously (which is the proper way):

function copyData(savPath, srcPath) {
    fs.readFile(srcPath, 'utf8', function (err, data) {
            if (err) throw err;
            //Do your processing, MD5, send a satellite to the moon, etc.
            fs.writeFile (savPath, data, function(err) {
                if (err) throw err;
                console.log('complete');
            });
        });
}

2.Do it synchronously. Your code won't have to change much, you will just need to replace readFile and writeFile by readFileSync and writeFileSync respectively. Warning: using this method is not only against best practises, but defies the very purpose of using nodejs (unless of course you have a very legitimate reason).

Edit: As per OP's request, here is one possible way to separate the two methods, e.g., using callbacks:

function getFileContent(srcPath, callback) { 
    fs.readFile(srcPath, 'utf8', function (err, data) {
        if (err) throw err;
        callback(data);
        }
    );
}

function copyFileContent(savPath, srcPath) { 
    getFileContent(srcPath, function(data) {
        fs.writeFile (savPath, data, function(err) {
            if (err) throw err;
            console.log('complete');
        });
    });
}

This way, you are separating the read part (in getFileContent) from the copy part.

Community
  • 1
  • 1
verybadalloc
  • 5,768
  • 2
  • 33
  • 49
  • From what your saying, it would be a frivolous waste of time to do this synchronously. I just thought it would be easier to section off readfile and writeful as seperate functions in case I would ever need to use just one and not the other within the program. Still, if I can do all the processing correctly, this works better. I will just have to try it and see if it works. – Todd Keck Jul 15 '13 at 04:49
  • Check out my edit for how to separate the read from the copying. You can apply the same technique to writeFile (e.g. passing a callback). – verybadalloc Jul 15 '13 at 05:07
  • I think it's an overstatement to say that doing this synchronously "defies the very purpose of using nodejs". Yes, it's true that nodejs makes possible, and encourages, a programming style in which any operation that could take a certain amount of time is done asynchronously. However, in this case the OP's purpose of using nodejs is simply to run a program written in javascript, and using synchronous calls might be a very appropriate style for a program like this. – Duncan May 29 '19 at 21:00
  • @Duncan "unless of course you have a very legitimate reason": simply running a program wirrten in JS is a legitimate reason – verybadalloc May 31 '19 at 10:09
5

I had to use this recently, so I converted verybadallocs answer to promises.

function readFile (srcPath) {
  return new Promise(function (resolve, reject) {
    fs.readFile(srcPath, 'utf8', function (err, data) {
      if (err) {
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

function writeFile (savPath, data) {
  return new Promise(function (resolve, reject) {
    fs.writeFile(savPath, data, function (err) {
      if (err) {
        reject(err)
      } else {
        resolve()
      }
    })
  })
}

Then using them is simple.

readFile('path').then(function (results) {
  results += ' test manipulation'
  return writeFile('path', results)
}).then(function () {
  //done writing file, can do other things
})

Usage for async/await

const results = await readFile('path')
results += ' test manipulation'
await writeFile('path', results)
// done writing file, can do other things
Trevor
  • 2,792
  • 1
  • 30
  • 43
0

To read and write a file with Non-blocking or Asynchronous way, you can use the advance features of es6 or higher like Promise or Async/await, but you must keep eye on Polyfills (https://javascript.info/polyfills) or if there are only a couple of read/write you can use call back Hell.

function readFiles(){
    fs.readFile('./txt/start.txt', 'utf-8', (err, data1)=>{
        if(err) return console.log(err);
        fs.readFile(`./txt/${data1}.txt`, 'utf-8', (err, data2)=>{
            if(err) return console.log(err);
            fs.readFile('./txt/append.txt', 'utf-8', (err, data3)=>{
                if(err) return console.log(err);
                writeFile('./txt/final.txt', `${data2}\n${data3}`);
            });
        });
    });
}

function writeFile(path, data){
    fs.writeFile(path,data,'utf-8',err=>{
        if(err){
            console.log(err);
        }
    })
}
readFiles();
Rafiq
  • 8,987
  • 4
  • 35
  • 35