在node.js中逐字符读取文件?

12

有没有一种方法在nodejs中从文件中逐个读取符号而不将整个文件存储在内存中? 我找到了一个关于按行读取的答案。

我尝试了类似这样的方法,但它没有帮助:

const stream = fs.createReadStream("walmart.dump", {
    encoding: 'utf8',
    fd: null,
    bufferSize: 1,
});
stream.on('data', function(sym){
    console.log(sym);
});
2个回答

15

可读流(Readable stream)具有 read() 方法,您可以通过这个方法传递每个要读取的块的字节长度。例如:

var readable = fs.createReadStream("walmart.dump", {
    encoding: 'utf8',
    fd: null,
});
readable.on('readable', function() {
  var chunk;
  while (null !== (chunk = readable.read(1) /* here */)) {
    console.log(chunk); // chunk is one byte
  }
});

2
这里有一种较低级的方法来实现:使用fs.read(fd, buffer, offset, length, position, callback)函数。
使用:
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);
        });

}

当你读取文件时,需要逐步增加位置,但这样可以正常工作。

下面是一个快速的例子,演示如何逐个字符读取整个文件。

为了好玩,我写了一个完整的脚本来实现它,只需传入不同的文件路径即可。

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);
});

正如您所看到的,每次读取文件时我们都会增加位置整数。希望操作系统在我们进行读取时将文件保留在内存中。使用async.whilst()可以,但我认为对于更具功能性的风格,最好不要将状态保留在函数顶部(ret和isByteRead)。我将把它留给读者来练习如何在不使用这些有状态变量的情况下实现此操作。


3
fs.openSync会一次性读取整个文件...这与 OP 想要的相反。 翻译后:fs.openSync函数会一次性读取整个文件,这与OP想要的相反。 - dopatraman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接