371
var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

Logs undefined, why?

3
  • 2
    fs.readFileSync also has cool features to read a file even if its in the unicode utf8 format. Commented May 10, 2017 at 23:37
  • N.B. fs.readFile can also do that ^ see my answer below Commented Dec 17, 2018 at 14:55
  • Duplicate of How do I return the response from an asynchronous call? Commented Nov 1, 2022 at 19:10

17 Answers 17

406

To elaborate on what @Raynos said, the function you have defined is an asynchronous callback. It doesn't execute right away, rather it executes when the file loading has completed. When you call readFile, control is returned immediately and the next line of code is executed. So when you call console.log, your callback has not yet been invoked, and this content has not yet been set. Welcome to asynchronous programming.

Example approaches

const fs = require('fs');
// First I want to read the file
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    const content = data;

    // Invoke the next step here however you like
    console.log(content);   // Put all of the code here (not the best solution)
    processFile(content);   // Or put the next step in a function and invoke it
});

function processFile(content) {
    console.log(content);
}

Or better yet, as Raynos example shows, wrap your call in a function and pass in your own callbacks. (Apparently this is better practice) I think getting into the habit of wrapping your async calls in function that takes a callback will save you a lot of trouble and messy code.

function doSomething (callback) {
    // any async callback invokes callback with response
}

doSomething (function doSomethingAfter(err, result) {
    // process the async result
});
Sign up to request clarification or add additional context in comments.

4 Comments

Sync I/O has its place — it's fine if you're doing a small build system or tool. On larger systems or server apps best practice is to avoid it.
Not everything is a web server. And there's nothing horrible about horrible about using sync versions of methods for one-shot calls before the server has started taking requests. Anyone using Node should really understand why before using it. Definitely before rant-blogging about it.
You have to include 'utf8' after the filename as an additional parameter, otherwise it will just return a buffer. See : stackoverflow.com/questions/9168737/…
324

There is actually a Synchronous function for this:

http://nodejs.org/api/fs.html#fs_fs_readfilesync_filename_encoding

Asynchronous

fs.readFile(filename, [encoding], [callback])

Asynchronously reads the entire contents of a file. Example:

fs.readFile('/etc/passwd', function (err, data) {
  if (err) throw err;
  console.log(data);
});

The callback is passed two arguments (err, data), where data is the contents of the file.

If no encoding is specified, then the raw buffer is returned.


SYNCHRONOUS

fs.readFileSync(filename, [encoding])

Synchronous version of fs.readFile. Returns the contents of the file named filename.

If encoding is specified then this function returns a string. Otherwise it returns a buffer.

var text = fs.readFileSync('test.md','utf8')
console.log (text)

5 Comments

Quick question, what is the use of the buffer that is being returned in synchronous version of readFile? If i read a file synchronously and do not pass any encoding, it prints buffer, how can i use this? Thank you.
I had experience with this recently. Let's say our buffer is data. if (Buffer.isBuffer( data){ result = data.toString('utf8'); } Now we have converted the buffer into readable text. This is good for reading a plaintext file or testing the file against format types. I could do a try/catch to see if it's a JSON file for example; but only after buffer is converted to text. Look here for more information: nodejs.org/api/buffer.html
Also as far as I know buffers are octet streams, and good for sending data "piece by piece." You must have seen that the buffer is something like AF 42 F1. Very practical for client-server-client communication.
You are missing the import of fs. It should be fs.promises.
@Logan is using the version with callback-based asynchrony instead of promise-based asynchrony.
126
function readContent(callback) {
    fs.readFile("./Index.html", function (err, content) {
        if (err) return callback(err)
        callback(null, content)
    })
}

readContent(function (err, content) {
    console.log(content)
})

3 Comments

Hi, in the first line of your code, function readContent(callback), is callback a reserved word? I mean, is this the standard way to implement callbacks for your custom functions? I've just started learning node.
Hi Amal. Callback is simply the argument passed to his function, it could be event or c or any name you like - it is not a reserved word in Javascript, and I would assume the same extends to Node.js.
readContent(function (err, content) gives me a syntax error when using the function as a parameter.
78

Using Promises with ES7

Asynchronous use with mz/fs

The mz module provides promisified versions of the core node library. Using them is simple. First install the library...

npm install mz

Then...

const fs = require('mz/fs');
fs.readFile('./Index.html').then(contents => console.log(contents))
  .catch(err => console.error(err));

Alternatively you can write them in asynchronous functions:

async function myReadfile () {
  try {
    const file = await fs.readFile('./Index.html');
  }
  catch (err) { console.error( err ) }
};

2 Comments

looks interesting. One typo: 'console.error(catch)' should be 'console.error(err)' I presume).
If you don't want to add an extra package, try @doctorlee 's solution below
30

This line will work,

const content = fs.readFileSync('./Index.html', 'utf8');
console.log(content);

3 Comments

7 years passed :) fs.readFileSync is sync method, so no need for await there. Await is useful with promises (nodejs.org/api/fs.html#fs_fs_promises_api), when you want to write async code with syntax similar to sync code.
@karaxuna, yeah. removed. I just come across this case today & I resolved using above code.
This is the simplest answer. If you don't need async, why in the world would you mix with the async version at all, with callbacks, async/await, etc?. This is the way to go.
25
var data = fs.readFileSync('tmp/reltioconfig.json','utf8');

use this for calling a file synchronously, without encoding its showing output as a buffer.

1 Comment

You need a blank line before code blocks in order for the pretty printing to kick in.
15

As said, fs.readFile is an asynchronous action. It means that when you tell node to read a file, you need to consider that it will take some time, and in the meantime, node continued to run the following code. In your case it's: console.log(content);.

It's like sending some part of your code for a long trip (like reading a big file).

Take a look at the comments that I've written:

var content;

// node, go fetch this file. when you come back, please run this "read" callback function
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});

// in the meantime, please continue and run this console.log
console.log(content);

That's why content is still empty when you log it. node has not yet retrieved the file's content.

This could be resolved by moving console.log(content) inside the callback function, right after content = data;. This way you will see the log when node is done reading the file and after content gets a value.

1 Comment

You should add the import to have a full example of readFile().
15

From Node v8

Use the built in promisify library to make these old callback functions more elegant.

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

async function doStuff() {
  try {
    const content = await readFile(filePath, 'utf8');
    console.log(content);
  } catch (e) {
    console.error(e);
  }
}

From Node v10

You can use the promises version of fs API:

import { promises as fs } from 'fs';

async function doStuff() {
  try {
    const content = await fs.readFile(filePath, 'utf8');
    console.log(content);
  } catch (e) {
    console.error(e);
  }
}

2 Comments

Can be in single line const doStuff = async (filePath) => fs.readFileSync(filePath, 'utf8');, no need of util.promisify wrap.
Not using the sync version is the point of this, and you should handle errors on calling it
12
const fs = require('fs')
function readDemo1(file1) {
    return new Promise(function (resolve, reject) {
        fs.readFile(file1, 'utf8', function (err, dataDemo1) {
            if (err)
                reject(err);
            else
                resolve(dataDemo1);
        });
    });
}
async function copyFile() {

    try {
        let dataDemo1 = await readDemo1('url')
        dataDemo1 += '\n' +  await readDemo1('url')

        await writeDemo2(dataDemo1)
        console.log(dataDemo1)
    } catch (error) {
        console.error(error);
    }
}
copyFile();

function writeDemo2(dataDemo1) {
    return new Promise(function(resolve, reject) {
      fs.writeFile('text.txt', dataDemo1, 'utf8', function(err) {
        if (err)
          reject(err);
        else
          resolve("Promise Success!");
      });
    });
  }

3 Comments

Please don't just put code in your answer... explain why it is different and how it solves the problem.
@doctorlee This actually works for me, without any external library. Explaination is require for sure.
Nearly 2024 and Node V. 21, please update the code to replace require with import.
10

sync and async file reading way:

//fs module to read file in sync and async way

var fs = require('fs'),
    filePath = './sample_files/sample_css.css';

// this for async way
/*fs.readFile(filePath, 'utf8', function (err, data) {
    if (err) throw err;
    console.log(data);
});*/

//this is sync way
var css = fs.readFileSync(filePath, 'utf8');
console.log(css);

Node Cheat Available at read_file.

Comments

8
var path = "index.html"

const readFileAsync = fs.readFileSync(path, 'utf8');
// console.log(readFileAsync)

using simple readFileSync works for me.

Comments

7
var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

This is just because node is asynchronous and it will not wait for the read function and as soon as the program starts it will console the value as undefined, Which is actually true because there is no value assigned to content variable. To handle we can use promises, generators etc. We can use promise in this way.

new Promise((resolve,reject)=>{
    fs.readFile('./index.html','utf-8',(err, data)=>{
        if (err) {
            reject(err); // in the case of error, control flow goes to the catch block with the error occured.
        }
        else{
            resolve(data);  // in the case of success, control flow goes to the then block with the content of the file.
        }
    });
})
.then((data)=>{
    console.log(data); // use your content of the file here (in this then).    
})
.catch((err)=>{
    throw err; //  handle error here.
})

Comments

6
var fs = require('fs');
var path = (process.cwd()+"\\text.txt");

fs.readFile(path , function(err,data)
{
    if(err)
        console.log(err)
    else
        console.log(data.toString());
});

Comments

5

The following is function would work for async wrap or promise then chains

const readFileAsync =  async (path) => fs.readFileSync(path, 'utf8');

2 Comments

You're not making the function async by putting an await on it, it will still do a sync read and return a promise that resolves straight away
readFileSync is sync function so use with await that isn't make scene . We should wrap readFile with util.promisify(readFile) then you can use await . Hope this help !!
3

you can read file by

var readMyFile = function(path, cb) {
      fs.readFile(path, 'utf8', function(err, content) {
        if (err) return cb(err, null);
        cb(null, content);
      });
    };

Adding on you can write to file,

var createMyFile = (path, data, cb) => {
  fs.writeFile(path, data, function(err) {
    if (err) return console.error(err);
    cb();
  });
};

and even chain it together

var readFileAndConvertToSentence = function(path, callback) {
  readMyFile(path, function(err, content) {
    if (err) {
      callback(err, null);
    } else {
      var sentence = content.split('\n').join(' ');
      callback(null, sentence);
    }
  });
};

Comments

3

To put it roughly, you're dealing with node.js which is asynchronous in nature.

When we talk about async, we're talking about doing or processing info or data while dealing with something else. It is not synonymous to parallel, please be reminded.

Your code:

var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

With your sample, it basically does the console.log part first, thus the variable 'content' being undefined.

If you really want the output, do something like this instead:

var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
    console.log(content);
});

This is asynchronous. It will be hard to get used to but, it is what it is. Again, this is a rough but fast explanation of what async is.

Comments

0

I like using fs-extra because all functions are promisified, right out of the box, so you can use await. So your code could look like this:

(async () => {
   try {
      const content = await fs.readFile('./Index.html');
      console.log(content);
   } catch (err) {
      console.error(err);
   }
})();

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.