Javascript nodejs同步逐行读取大文件?

Javascript nodejs同步逐行读取大文件?,javascript,node.js,filesystems,mojibake,Javascript,Node.js,Filesystems,Mojibake,我有一个大文件(utf8)。我知道fs.createReadStream可以创建流来读取大文件,但不同步。所以我尝试使用fs.readSync,但读取的文本像一样被破坏迈�" 使用: fs.readFileSync(文件名,[编码])的同步版本 返回文件名的内容 如果指定了编码,则此函数返回一个字符串。 否则它将返回一个缓冲区 另一方面,由于您使用的是node,我建议您使用异步函数。两个潜在问题 3字节BOM在开始时没有跳过 前4个字节不能很好地格式化为UTF8的字符(UTF8不是固定长度) 对

我有一个大文件(utf8)。我知道
fs.createReadStream
可以创建流来读取大文件,但不同步。所以我尝试使用
fs.readSync
,但读取的文本像
一样被破坏迈�"

使用:

fs.readFileSync(文件名,[编码])的同步版本 返回文件名的内容

如果指定了编码,则此函数返回一个字符串。 否则它将返回一个缓冲区


另一方面,由于您使用的是node,我建议您使用异步函数。

两个潜在问题

  • 3字节BOM在开始时没有跳过
  • 前4个字节不能很好地格式化为UTF8的字符(UTF8不是固定长度)

  • 对于大型文件,
    readFileSync
    可能会带来不便,因为它会将整个文件加载到内存中。另一种同步方法是迭代调用
    readSync
    ,一次读取少量数据,并在行出现时对行进行处理。以下代码位实现了此方法并同步处理一行每次从文件“test.txt”中:

    var fs = require('fs');
    var filename = 'test.txt'
    
    var fd = fs.openSync(filename, 'r');
    var bufferSize = 1024;
    var buffer = new Buffer(bufferSize);
    
    var leftOver = '';
    var read, line, idxStart, idx;
    while ((read = fs.readSync(fd, buffer, 0, bufferSize, null)) !== 0) {
      leftOver += buffer.toString('utf8', 0, read);
      idxStart = 0
      while ((idx = leftOver.indexOf("\n", idxStart)) !== -1) {
        line = leftOver.substring(idxStart, idx);
        console.log("one line read: " + line);
        idxStart = idx + 1;
      }
      leftOver = leftOver.substring(idxStart);
    }
    
    使用


    我在JB Kohn的答案中构建了一个更简单的版本,在缓冲区中使用split(),它可以处理我尝试过的较大文件

    /*
     * Synchronously call fn(text, lineNum) on each line read from file descriptor fd.
     */
    function forEachLine (fd, fn) {
        var bufSize = 64 * 1024;
        var buf = new Buffer(bufSize);
        var leftOver = '';
        var lineNum = 0;
        var lines, n;
    
        while ((n = fs.readSync(fd, buf, 0, bufSize, null)) !== 0) {
            lines = buf.toString('utf8', 0 , n).split('\n');
            lines[0] = leftOver+lines[0];       // add leftover string from previous read
            while (lines.length > 1) {          // process all but the last line
                fn(lines.shift(), lineNum);
                lineNum++;
            }
            leftOver = lines.shift();           // save last line fragment (may be '')
        }
        if (leftOver) {                         // process any remaining line
            fn(leftOver, lineNum);
        }
    }
    

    你确定文件是用utf8编码的吗?是的,Unicode(UTF-8)和Unix(LF)我想你指的是“同步”而不是“同步”“。我发布了一个类似问题的解决方案,用于使用同步流解析一个非常大的文件。看:@nroe,那你为什么要求同步读取?当然,这对大文件不起作用。@Tom,nroe可能希望能够接收这些行作为read调用的返回值。一些实现此功能的代码在中可用(不是我的)。是否可以将
    split('\n')
    更改为
    split(/\r?\n/)
    以支持可能的windows行结尾?
    var lineByLine = require('n-readlines');
    var liner = new lineByLine('./textFile.txt');
    
    var line;
    var lineNumber = 0;
    while (line = liner.next()) {
        console.log('Line ' + lineNumber + ': ' + line.toString('ascii'));
        lineNumber++;
    }
    
    console.log('end of line reached');
    
    /*
     * Synchronously call fn(text, lineNum) on each line read from file descriptor fd.
     */
    function forEachLine (fd, fn) {
        var bufSize = 64 * 1024;
        var buf = new Buffer(bufSize);
        var leftOver = '';
        var lineNum = 0;
        var lines, n;
    
        while ((n = fs.readSync(fd, buf, 0, bufSize, null)) !== 0) {
            lines = buf.toString('utf8', 0 , n).split('\n');
            lines[0] = leftOver+lines[0];       // add leftover string from previous read
            while (lines.length > 1) {          // process all but the last line
                fn(lines.shift(), lineNum);
                lineNum++;
            }
            leftOver = lines.shift();           // save last line fragment (may be '')
        }
        if (leftOver) {                         // process any remaining line
            fn(leftOver, lineNum);
        }
    }