我想把一个非常非常大的文件读入node。js中的JavaScript数组。

所以,如果文件是这样的:

first line
two 
three
...
...

我有一个数组:

['first line','two','three', ... , ... ] 

函数看起来是这样的:

var array = load(filename); 

因此,将其全部作为字符串加载,然后将其拆分的想法是不可接受的。


当前回答

我只是想添加@finbarr伟大的答案,在异步的例子中的一个小修复:

异步:

var fs = require('fs');
fs.readFile('file.txt', function(err, data) {
    if(err) throw err;
    var array = data.toString().split("\n");
    for(i in array) {
        console.log(array[i]);
    }
    done();
});

@ madphysics, done()释放async。调用。

其他回答

这是@mtomis上面回答的一个变体。

它创建了一个行流。它发出'data'和'end'事件,允许您处理流的结束。

var events = require('events');

var LineStream = function (input) {
    var remaining = '';

    input.on('data', function (data) {
        remaining += data;
        var index = remaining.indexOf('\n');
        var last = 0;
        while (index > -1) {
            var line = remaining.substring(last, index);
            last = index + 1;
            this.emit('data', line);
            index = remaining.indexOf('\n', last);
        }
        remaining = remaining.substring(last);
    }.bind(this));

    input.on('end', function() {
        if (remaining.length > 0) {
            this.emit('data', remaining);
        }
        this.emit('end');
    }.bind(this));
}

LineStream.prototype = new events.EventEmitter;

用它来包装:

var lineInput = new LineStream(input);

lineInput.on('data', function (line) {
    // handle line
});

lineInput.on('end', function() {
    // wrap it up
});

使用Node.js v8或更高版本有一个新特性,可以将普通函数转换为异步函数。

util.promisify

这是一个很棒的功能。下面是将txt文件中的10000个数字解析为一个数组的示例,使用归并排序对数字进行逆序计数。

// read from txt file
const util = require('util');
const fs = require('fs')
fs.readFileAsync = util.promisify(fs.readFile);
let result = []

const parseTxt = async (csvFile) => {
  let fields, obj
  const data = await fs.readFileAsync(csvFile)
  const str = data.toString()
  const lines = str.split('\r\n')
  // const lines = str
  console.log("lines", lines)
  // console.log("str", str)

  lines.map(line => {
    if(!line) {return null}
    result.push(Number(line))
  })
  console.log("result",result)
  return result
}
parseTxt('./count-inversion.txt').then(() => {
  console.log(mergeSort({arr: result, count: 0}))
})

如果你能把最终的数据放入一个数组,那么你不也能把它放入一个字符串中并分割它吗? 在任何情况下,如果你想一次处理一行文件,你也可以尝试这样做:

var fs = require('fs');

function readLines(input, func) {
  var remaining = '';

  input.on('data', function(data) {
    remaining += data;
    var index = remaining.indexOf('\n');
    while (index > -1) {
      var line = remaining.substring(0, index);
      remaining = remaining.substring(index + 1);
      func(line);
      index = remaining.indexOf('\n');
    }
  });

  input.on('end', function() {
    if (remaining.length > 0) {
      func(remaining);
    }
  });
}

function func(data) {
  console.log('Line: ' + data);
}

var input = fs.createReadStream('lines.txt');
readLines(input, func);

编辑:(回应phopkins的评论)我认为(至少在新版本中)substring不复制数据,而是创建一个特殊的SlicedString对象(从v8源代码中快速浏览)。在任何情况下,这里有一个修改,避免了提到的子字符串(在一个文件上测试了几个兆字节的“只工作不玩耍,聪明的孩子会变傻”):

function readLines(input, func) {
  var remaining = '';

  input.on('data', function(data) {
    remaining += data;
    var index = remaining.indexOf('\n');
    var last  = 0;
    while (index > -1) {
      var line = remaining.substring(last, index);
      last = index + 1;
      func(line);
      index = remaining.indexOf('\n', last);
    }

    remaining = remaining.substring(last);
  });

  input.on('end', function() {
    if (remaining.length > 0) {
      func(remaining);
    }
  });
}

我只是想添加@finbarr伟大的答案,在异步的例子中的一个小修复:

异步:

var fs = require('fs');
fs.readFile('file.txt', function(err, data) {
    if(err) throw err;
    var array = data.toString().split("\n");
    for(i in array) {
        console.log(array[i]);
    }
    done();
});

@ madphysics, done()释放async。调用。

本质上,这将完成工作:.replace(/\r\n/g,'\n').split('\n')。 这适用于Mac, Linux和Windows。

代码片段

同步:

const { readFileSync } = require('fs');

const array = readFileSync('file.txt').toString().replace(/\r\n/g,'\n').split('\n');

for(let i of array) {
    console.log(i);
}

异步:

用fs。promises API提供了另一组异步文件系统方法,返回Promise对象而不是使用回调。(不需要承诺,你也可以使用async-await,在Node.js 10.0.0版本之后可用)

const { readFile } = require('fs').promises;

readFile('file.txt', function(err, data) {
    if(err) throw err;

    const arr = data.toString().replace(/\r\n/g,'\n').split('\n');

    for(let i of arr) {
        console.log(i);
    }
});

更多关于\r和\n的信息在这里:\r\n, \r和\n它们之间有什么区别?