Here's a lower-level way to do it: fs.read(fd, buffer, offset, length, position, callback)
using: 
const fs = require('fs');
// open file for reading, returns file descriptor
const fd = fs.openSync('your-file.txt','r');
function readOneCharFromFile(position, cb){
        // only need to store one byte (one character)
        const b = new Buffer(1);
        fs.read(fd, b, 0, 1, position, function(err,bytesRead, buffer){
            console.log('data => ', String(buffer));
            cb(err,buffer);
        });
}
you will have to increment the position, as you read the file, but it will work.
here's a quick example of how to read a whole file, character by character
Just for fun I wrote this complete script to do it, just pass in a different file path, and it should work
const async = require('async');
const fs = require('fs');
const path = require('path');
function read(fd, position, cb) {
    let isByteRead = null;
    let ret = new Buffer(0);
    async.whilst(
        function () {
            return isByteRead !== false;
        },
        function (cb) {
            readOneCharFromFile(fd, position++, function (err, bytesRead, buffer) {
                if(err){
                    return cb(err);
                }
                isByteRead = !!bytesRead;
                if(isByteRead){
                    ret = Buffer.concat([ret,buffer]);
                }
                cb(null);
            });
        },
        function (err) {
            cb(err, ret);
        }
    );
}
function readOneCharFromFile(fd, position, cb) {
    // only need to store one byte (one character)
    const b = new Buffer(1);
    fs.read(fd, b, 0, 1, position, cb);
}
 /// use your own file here
const file = path.resolve(__dirname + '/fixtures/abc.txt');
const fd = fs.openSync(file, 'r');
// start reading at position 0, position will be incremented
read(fd, 0, function (err, data) {
    if (err) {
        console.error(err.stack || err);
    }
    else {
        console.log('data => ', String(data));
    }
    fs.closeSync(fd);
});
As you can see we increment the position integer every time we read the file. Hopefully the OS keeps the file in memory as we go. Using async.whilst() is OK, but I think for a more functional style it's better not to keep the state in the top of the function (ret and isByteRead). I will leave it as an exercise to the reader to implement this without using those stateful variables.