node.js:将文本文件读入数组。 (每一行都是数组中的一个项目。)
Posted
技术标签:
【中文标题】node.js:将文本文件读入数组。 (每一行都是数组中的一个项目。)【英文标题】:node.js: read a text file into an array. (Each line an item in the array.) 【发布时间】:2011-10-13 11:59:50 【问题描述】:我想将一个非常非常大的文件读入 node.js 中的 javascript 数组。
那么,如果文件是这样的:
first line
two
three
...
...
我会得到数组:
['first line','two','three', ... , ... ]
函数如下所示:
var array = load(filename);
因此,将其全部加载为字符串然后拆分的想法是不可接受的。
【问题讨论】:
这个问题需要认真编辑和清理。它说将一个文本文件读入一个数组,但是当您阅读所有答案和 cmets 时,它实际上意味着一次读取一个文本文件。对于这个问题,@zswang 给出了迄今为止最好的答案。 是的,只需读取该文件并将每一行推入一个数组:***.com/a/34033928/1536309 【参考方案1】:同步:
var fs = require('fs');
var array = fs.readFileSync('file.txt').toString().split("\n");
for(i in array)
console.log(array[i]);
异步:
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]);
);
【讨论】:
谢谢。不幸的是,我不得不编辑我的问题。我的意思是如何读取一个巨大的文件。在字符串中读取它是不可接受的。 我发现在 Windows 制作的文件上执行此操作,我不得不拆分 \r\n 但这破坏了 Mac;所以更健壮; _array = string.replace(/\r\n/g,'\n').split('\n');为两者工作 +1 *** 中存在一些问题。现在,我经常在向下滚动太远后找到投票率很高的答案。这也是一个例子。它的投票率最高,但位于页面底部,排在最后。我认为 *** 需要改进他们的排序算法。 @shashwat 提出问题的人可以决定哪个是正确的答案。在这种情况下,他们需要一个针对大文件的流式解决方案,并且将整个文件放在一个字符串中是不可接受的。 SO 没什么错,真的。 @WillHancock 为什么不使用os.EOL
而不是那种怪物?【参考方案2】:
如果您可以将最终数据放入数组中,那么您是否也可以将其放入字符串中并按照建议进行拆分? 在任何情况下,如果您想一次处理一行文件,您也可以尝试以下操作:
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 的评论)我认为(至少在较新的版本中)子字符串不会复制数据,而是创建一个特殊的 SlicedString 对象(来自快速浏览 v8 源代码)。无论如何,这里有一个修改,它避免了提到的子字符串(在一个价值几兆字节的文件上测试了“All work and no play makes Jack a dull boy”):
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);
);
【讨论】:
谢谢。回答你的问题:不,字符串太大了。 我在大约 2MB 左右的文件上尝试了这个,它非常慢,比将文件同步读取到字符串要慢得多。我认为问题是剩余的 = remaining.substring 行。 Node 的“数据”一次可能会给你很多,并且对每一行进行复制很快就会变成 O(n^2)。 @Finbar 的回答要好得多【参考方案3】:带有BufferedReader,但函数应该是异步的:
var load = function (file, cb)
var lines = [];
new BufferedReader (file, encoding: "utf8" )
.on ("error", function (error)
cb (error, null);
)
.on ("line", function (line)
lines.push (line);
)
.on ("end", function ()
cb (null, lines);
)
.read ();
;
load ("file", function (error, lines)
if (error) return console.log (error);
console.log (lines);
);
【讨论】:
【参考方案4】:使用 Node.js readline module。
var fs = require('fs');
var readline = require('readline');
var filename = process.argv[2];
readline.createInterface(
input: fs.createReadStream(filename),
terminal: false
).on('line', function(line)
console.log('Line: ' + line);
);
【讨论】:
遗憾的是,此解决方案存在一个问题:如果文件末尾没有\n
,则不会得到最后一行!见:***.com/questions/18450197/…
Node 已通过 \n ***.com/a/32599033/3763850 修复了该问题【参考方案5】:
这是@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
);
【讨论】:
您将以在实例之间共享事件结束。var EventEmitter = require('events').EventEmitter; var util = require('util'); function GoodEmitter() EventEmitter.call(this); util.inherits(GoodEmitter, EventEmitter);
你到底在说什么实例?
尝试创建var li1 = new LineStream(input1), li2 = new LineStream(input2);
,然后计算每个'end'被触发的次数
试过了。 'end' 为每个实例触发一次。 var fs = require('fs'); var input1 = fs.createReadStream('text.txt'); var ls1 = new LineStream(input1); ls1.on('data', function (line) console.log('1:line=' + line); ); ls1.on('end', function (line) console.log('1:fin'); ); var input2 = fs.createReadStream('text.txt'); var ls2 = new LineStream(input2); ls2.on('data', function (line) console.log('2:line=' + line); ); ls2.on('end', function (line) console.log('2:fin'); );
输出:文本文件中的每一行都针对每个实例触发一次。 “结束”也是如此。【参考方案6】:
我遇到了同样的问题,我已经用模块逐行解决了
https://www.npmjs.com/package/line-by-line
至少对我来说,在同步和异步模式下都像一个魅力。
另外,行终止不终止 \n 的问题可以通过以下选项解决:
encoding: 'utf8', skipEmptyLines: false
行的同步处理:
var LineByLineReader = require('line-by-line'),
lr = new LineByLineReader('big_file.txt');
lr.on('error', function (err)
// 'err' contains error object
);
lr.on('line', function (line)
// 'line' contains the current line without the trailing newline character.
);
lr.on('end', function ()
// All lines are read, file is closed now.
);
【讨论】:
【参考方案7】:使用 readline (documentation)。这是一个读取css文件,解析图标并将它们写入json的示例
var results = [];
var rl = require('readline').createInterface(
input: require('fs').createReadStream('./assets/stylesheets/_icons.scss')
);
// for every new line, if it matches the regex, add it to an array
// this is ugly regex :)
rl.on('line', function (line)
var re = /\.icon-icon.*:/;
var match;
if ((match = re.exec(line)) !== null)
results.push(match[0].replace(".",'').replace(":",''));
);
// readline emits a close event when the file is read.
rl.on('close', function()
var outputFilename = './icons.json';
fs.writeFile(outputFilename, JSON.stringify(results, null, 2), function(err)
if(err)
console.log(err);
else
console.log("JSON saved to " + outputFilename);
);
);
【讨论】:
【参考方案8】:file.lines
和我的JFile package
伪
var JFile=require('jfile');
var myF=new JFile("./data.txt");
myF.lines // ["first line","second line"] ....
别忘了之前:
npm install jfile --save
【讨论】:
这篇文章被正确地标记为垃圾邮件,因为你没有在帖子中指出 JFile 包是你的。请编辑您提到 JFile 的其他帖子以添加此信息。谢谢。 它被提到了 6 年。你有没有注意到第一句话中的“我的”这个词!! @StephenRauch 您是否注意到我在第一句话中加入了“我的”一词。如果这是您的偏好,我可以简单地将它们全部标记为垃圾邮件。 哦!惊人的!谢谢@StephenRauch!这是非常古老的答案。 是的,但还有更多,我希望您以类似于我更新这个的方式更新它们。【参考方案9】:我只想添加@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();
);
@MadPhysicist,done() 是释放异步的原因。打电话。
【讨论】:
【参考方案10】:要将大文件读入数组,您可以逐行或逐块读取。
一行一行参考my answer here
var fs = require('fs'),
es = require('event-stream'),
var lines = [];
var s = fs.createReadStream('filepath')
.pipe(es.split())
.pipe(es.mapSync(function(line)
//pause the readstream
s.pause();
lines.push(line);
s.resume();
)
.on('error', function(err)
console.log('Error:', err);
)
.on('end', function()
console.log('Finish reading.');
console.log(lines);
)
);
逐块参考this article
var offset = 0;
var chunkSize = 2048;
var chunkBuffer = new Buffer(chunkSize);
var fp = fs.openSync('filepath', 'r');
var bytesRead = 0;
while(bytesRead = fs.readSync(fp, chunkBuffer, 0, chunkSize, offset))
offset += bytesRead;
var str = chunkBuffer.slice(0, bytesRead).toString();
var arr = str.split('\n');
if(bytesRead = chunkSize)
// the last item of the arr may be not a full line, leave it to the next chunk
offset -= arr.pop().length;
lines.push(arr);
console.log(lines);
【讨论】:
【参考方案11】:使用 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))
)
【讨论】:
【参考方案12】:js:
var array = fs.readFileSync('file.txt', 'utf8').split('\n');
ts:
var array = fs.readFileSync('file.txt', 'utf8').toString().split('\n');
【讨论】:
为了防止上面抛出TypeError: fs.readFileSync(...).split is not a function
,你应该像这样使用.toString():var array = fs.readFileSync('file.txt', 'utf8').toString().split('\n');
【参考方案13】:
基本上这将完成这项工作:.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 and \n what is the difference between them?
【讨论】:
以上是关于node.js:将文本文件读入数组。 (每一行都是数组中的一个项目。)的主要内容,如果未能解决你的问题,请参考以下文章
打开一个文本文件,每次读取一行内容,将每一行作为String读入,并将Sring对象置入LinkedList中,按相反顺序打印出LinkList所有行.