node.js에서 한 번에 한 줄씩 파일을 읽습니까?
한 번에 한 줄씩 큰 파일을 읽으려고합니다. Quora 에서 주제를 다루는 질문을 찾았 지만 모든 것을 함께 맞추기위한 연결이 누락되었습니다.
var Lazy=require("lazy");
new Lazy(process.stdin)
.lines
.forEach(
function(line) {
console.log(line.toString());
}
);
process.stdin.resume();
내가 알아 내고 싶은 것은이 샘플에서와 같이 STDIN 대신 파일에서 한 번에 한 줄씩 읽는 방법입니다.
나는 시도했다 :
fs.open('./VeryBigFile.csv', 'r', '0666', Process);
function Process(err, fd) {
if (err) throw err;
// DO lazy read
}
하지만 작동하지 않습니다. 나는 핀치로 PHP와 같은 것을 다시 사용할 수 있다는 것을 알고 있지만 이것을 알아 내고 싶습니다.
파일을 실행하는 서버가 메모리를 가지고있는 것보다 훨씬 커서 다른 대답이 효과가 있다고 생각하지 않습니다.
Node.js v0.12부터 Node.js v4.0.0부터 안정적인 readline 코어 모듈이 있습니다. 외부 모듈없이 파일에서 행을 읽는 가장 쉬운 방법은 다음과 같습니다.
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream('file.in')
});
lineReader.on('line', function (line) {
console.log('Line from file:', line);
});
final이 없어도 마지막 행은 올바르게 읽습니다 (Node v0.12 이상) \n
.
업데이트 :이 예제는 노드의 API 공식 문서 에 추가 되었습니다 .
이러한 간단한 작업을 위해 타사 모듈에 의존해서는 안됩니다. 쉬워
var fs = require('fs'),
readline = require('readline');
var rd = readline.createInterface({
input: fs.createReadStream('/path/to/file'),
output: process.stdout,
console: false
});
rd.on('line', function(line) {
console.log(line);
});
당신은 필요 없어 open
파일, 대신, 당신은을 만들어야합니다 ReadStream
.
그런 다음 해당 스트림을 Lazy
파일을 줄을 읽기위한 아주 좋은 모듈이, 그것은라고 선 리더
그것으로 당신은 단순히 작성 :
var lineReader = require('line-reader');
lineReader.eachLine('file.txt', function(line, last) {
console.log(line);
// do whatever you want with line...
if(last){
// or check if it's the last one
}
});
더 많은 제어가 필요한 경우 "java 스타일"인터페이스를 사용하여 파일을 반복 할 수도 있습니다.
lineReader.open('file.txt', function(reader) {
if (reader.hasNextLine()) {
reader.nextLine(function(line) {
console.log(line);
});
}
});
require('fs').readFileSync('file.txt', 'utf-8').split(/\r?\n/).forEach(function(line){
console.log(line);
})
오래된 주제이지만 작동합니다.
var rl = readline.createInterface({
input : fs.createReadStream('/path/file.txt'),
output: process.stdout,
terminal: false
})
rl.on('line',function(line){
console.log(line) //or parse line
})
단순한. 외부 모듈이 필요 없습니다.
언제든지 자신의 라인 리더를 굴릴 수 있습니다. 이 스 니펫을 아직 벤치마킹하지는 않았지만 들어오는 청크 스트림을 후행 '\ n'없이 줄로 올바르게 분할합니다.
var last = "";
process.stdin.on('data', function(chunk) {
var lines, i;
lines = (last+chunk).split("\n");
for(i = 0; i < lines.length - 1; i++) {
console.log("line: " + lines[i]);
}
last = lines[i];
});
process.stdin.on('end', function() {
console.log("line: " + last);
});
process.stdin.resume();
로그 구문 분석 중에 데이터를 축적 해야하는 빠른 로그 구문 분석 스크립트에서 작업 할 때이 문제를 해결했으며 perl 또는 bash 대신 js 및 node를 사용하여 시도하는 것이 좋을 것이라고 생각했습니다.
어쨌든 작은 nodejs 스크립트는 자체 포함되어야하며 타사 모듈에 의존해서는 안된다고 생각 하므로이 질문에 대한 모든 답변을 읽은 후 각 모듈을 사용하여 라인 파싱을 처리하면 13 SLOC 기본 nodejs 솔루션이 관심을 가질 수 있습니다.
와 캐리어 모듈 :
var carrier = require('carrier');
process.stdin.resume();
carrier.carry(process.stdin, function(line) {
console.log('got one line: ' + line);
});
2019 년 업데이트
공식 Nodejs 문서에 멋진 예제가 이미 게시되어 있습니다. 여기
이를 위해서는 최신 Nodejs가 시스템에 설치되어 있어야합니다. > 11.4
const fs = require('fs');
const readline = require('readline');
async function processLineByLine() {
const fileStream = fs.createReadStream('input.txt');
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
// Note: we use the crlfDelay option to recognize all instances of CR LF
// ('\r\n') in input.txt as a single line break.
for await (const line of rl) {
// Each line in input.txt will be successively available here as `line`.
console.log(`Line from file: ${line}`);
}
}
processLineByLine();
노드를 작동시키는 드레인 / 일시 정지 / 재개 방법으로 인해 해당 라인을 처리하고 다른 스트림에 쓰려고 할 때 Lazy를 사용하여 방대한 대량의 메모리 누수가 발생했습니다 ( http : // elegantcode 참조). .com / 2011 / 04 / 06 / taking-baby-steps-with-node-js-pumping-data-between-streams / (나는이 사람을 사랑합니다). 나는 왜 Lazy를 정확히 이해했는지 충분히 자세히 보지 못했지만 Lazy 종료없이 드레인을 허용하기 위해 읽기 스트림을 일시 중지 할 수 없었습니다.
방대한 CSV 파일을 XML 문서로 처리하는 코드를 작성했습니다. https://github.com/j03m/node-csv2xml
Lazy 라인으로 이전 버전을 실행하면 누출이 발생합니다. 최신 개정판은 전혀 누출되지 않으며 독자 / 프로세서의 기초로 사용할 수 있습니다. 거기에 몇 가지 맞춤 정보가 있지만.
편집 : 필자는 필연적으로 배수 / 일시 중지 / 다시 시작하는 충분히 큰 XML 조각을 작성하는 것을 알 때까지 Lazy를 사용한 코드가 제대로 작동했음을 알 수 있습니다. 작은 덩어리에 대해서는 괜찮 았습니다.
편집하다:
변환 스트림을 사용하십시오 .
BufferedReader 를 사용하면 행을 읽을 수 있습니다.
new BufferedReader ("lorem ipsum", { encoding: "utf8" })
.on ("error", function (error){
console.log ("error: " + error);
})
.on ("line", function (line){
console.log ("line: " + line);
})
.on ("end", function (){
console.log ("EOF");
})
.read ();
원래의 답변을 게시 한 후 split 은 파일의 줄 읽기에 노드 모듈을 사용하는 것이 매우 쉽다는 것을 알았습니다 . 선택적 매개 변수도 허용합니다.
var split = require('split');
fs.createReadStream(file)
.pipe(split())
.on('data', function (line) {
//each chunk now is a seperate line!
});
매우 큰 파일에서는 테스트하지 않았습니다. 당신이 할 경우 알려주십시오.
이에 대한 포괄적 인 솔루션이 부족하여 좌절했기 때문에 내 시도 ( git / npm )를 모았습니다 . 복사하여 붙여 넣은 기능 목록 :
- 대화식 회선 처리 (콜백 기반, 전체 파일을 RAM으로로드하지 않음)
- 선택적으로 배열의 모든 행을 반환합니다 (상세 또는 원시 모드)
- 대화식으로 스트리밍 중단 또는 처리와 같은 맵 / 필터 수행
- 개행 규칙 감지 (PC / Mac / Linux)
- 올바른 eof / 마지막 라인 처리
- 멀티 바이트 UTF-8 문자의 올바른 처리
- 라인 단위로 바이트 오프셋 및 바이트 길이 정보 검색
- 라인 기반 또는 바이트 기반 오프셋을 사용한 임의 액세스
- 임의의 액세스 속도를 높이기 위해 라인 오프셋 정보를 자동으로 매핑
- 종속성 없음
- 테스트
NIH? 당신은 결정 :-)
function createLineReader(fileName){
var EM = require("events").EventEmitter
var ev = new EM()
var stream = require("fs").createReadStream(fileName)
var remainder = null;
stream.on("data",function(data){
if(remainder != null){//append newly received data chunk
var tmp = new Buffer(remainder.length+data.length)
remainder.copy(tmp)
data.copy(tmp,remainder.length)
data = tmp;
}
var start = 0;
for(var i=0; i<data.length; i++){
if(data[i] == 10){ //\n new line
var line = data.slice(start,i)
ev.emit("line", line)
start = i+1;
}
}
if(start<data.length){
remainder = data.slice(start);
}else{
remainder = null;
}
})
stream.on("end",function(){
if(null!=remainder) ev.emit("line",remainder)
})
return ev
}
//---------main---------------
fileName = process.argv[2]
lineReader = createLineReader(fileName)
lineReader.on("line",function(line){
console.log(line.toString())
//console.log("++++++++++++++++++++")
})
대부분의 경우이 정도면 충분합니다.
const fs = require("fs")
fs.readFile('./file', 'utf-8', (err, file) => {
const lines = file.split('\n')
for (let line of lines)
console.log(line)
});
나는 기본적으로 Perl에서이 같은 문제를 해결하고 싶었다.
while (<>) {
process_line($_);
}
내 유스 케이스는 서버가 아닌 독립형 스크립트 였기 때문에 동기가 좋았습니다. 이것들은 나의 기준이었습니다.
- 많은 프로젝트에서 재사용 할 수있는 최소 동기 코드입니다.
- 파일 크기 또는 줄 수에 제한이 없습니다.
- 줄 길이에는 제한이 없습니다.
- BMP 이외의 문자를 포함하여 UTF-8로 전체 유니 코드를 처리 할 수 있습니다.
- * nix 및 Windows 줄 끝을 처리 할 수 있습니다 (구식 Mac은 필요하지 않음).
- 줄 끝 문자는 줄에 포함될 문자입니다.
- 줄 끝 문자가 있거나없는 마지막 줄을 처리 할 수 있습니다.
- node.js 배포에 포함되지 않은 외부 라이브러리를 사용하지 마십시오.
이것은 node.js의 저수준 스크립팅 유형 코드에 대한 느낌을 얻고 Perl과 같은 다른 스크립팅 언어를 대체하는 방법을 결정하는 프로젝트입니다.
놀라운 노력과 몇 가지 잘못된 시작 후에 이것은 내가 생각해 낸 코드입니다. 내가 예상했던 것보다 빠르지 만 사소한 것입니다 : (GitHub에서 포크)
var fs = require('fs'),
StringDecoder = require('string_decoder').StringDecoder,
util = require('util');
function lineByLine(fd) {
var blob = '';
var blobStart = 0;
var blobEnd = 0;
var decoder = new StringDecoder('utf8');
var CHUNK_SIZE = 16384;
var chunk = new Buffer(CHUNK_SIZE);
var eolPos = -1;
var lastChunk = false;
var moreLines = true;
var readMore = true;
// each line
while (moreLines) {
readMore = true;
// append more chunks from the file onto the end of our blob of text until we have an EOL or EOF
while (readMore) {
// do we have a whole line? (with LF)
eolPos = blob.indexOf('\n', blobStart);
if (eolPos !== -1) {
blobEnd = eolPos;
readMore = false;
// do we have the last line? (no LF)
} else if (lastChunk) {
blobEnd = blob.length;
readMore = false;
// otherwise read more
} else {
var bytesRead = fs.readSync(fd, chunk, 0, CHUNK_SIZE, null);
lastChunk = bytesRead !== CHUNK_SIZE;
blob += decoder.write(chunk.slice(0, bytesRead));
}
}
if (blobStart < blob.length) {
processLine(blob.substring(blobStart, blobEnd + 1));
blobStart = blobEnd + 1;
if (blobStart >= CHUNK_SIZE) {
// blobStart is in characters, CHUNK_SIZE is in octets
var freeable = blobStart / CHUNK_SIZE;
// keep blob from growing indefinitely, not as deterministic as I'd like
blob = blob.substring(CHUNK_SIZE);
blobStart -= CHUNK_SIZE;
blobEnd -= CHUNK_SIZE;
}
} else {
moreLines = false;
}
}
}
아마도 더 정리 될 수 있으며 시행 착오의 결과였습니다.
발전기 기반 라인 리더 : https://github.com/neurosnap/gen-readlines
var fs = require('fs');
var readlines = require('gen-readlines');
fs.open('./file.txt', 'r', function(err, fd) {
if (err) throw err;
fs.fstat(fd, function(err, stats) {
if (err) throw err;
for (var line of readlines(fd, stats.size)) {
console.log(line.toString());
}
});
});
파일을 한 줄씩 읽고 다른 파일로 작성하려면 다음을 수행하십시오.
var fs = require('fs');
var readline = require('readline');
var Stream = require('stream');
function readFileLineByLine(inputFile, outputFile) {
var instream = fs.createReadStream(inputFile);
var outstream = new Stream();
outstream.readable = true;
outstream.writable = true;
var rl = readline.createInterface({
input: instream,
output: outstream,
terminal: false
});
rl.on('line', function (line) {
fs.appendFileSync(outputFile, line + '\n');
});
};
var fs = require('fs');
function readfile(name,online,onend,encoding) {
var bufsize = 1024;
var buffer = new Buffer(bufsize);
var bufread = 0;
var fd = fs.openSync(name,'r');
var position = 0;
var eof = false;
var data = "";
var lines = 0;
encoding = encoding || "utf8";
function readbuf() {
bufread = fs.readSync(fd,buffer,0,bufsize,position);
position += bufread;
eof = bufread ? false : true;
data += buffer.toString(encoding,0,bufread);
}
function getLine() {
var nl = data.indexOf("\r"), hasnl = nl !== -1;
if (!hasnl && eof) return fs.closeSync(fd), online(data,++lines), onend(lines);
if (!hasnl && !eof) readbuf(), nl = data.indexOf("\r"), hasnl = nl !== -1;
if (!hasnl) return process.nextTick(getLine);
var line = data.substr(0,nl);
data = data.substr(nl+1);
if (data[0] === "\n") data = data.substr(1);
online(line,++lines);
process.nextTick(getLine);
}
getLine();
}
나는 같은 문제가 있었고 위의 해결책을 생각해 냈지만 다른 사람들에게는 비슷해 보이지만 async이며 대용량 파일을 매우 빠르게 읽을 수 있습니다
이것이 도움이되기를 바랍니다.
나는이 잘 수행하고 꽤 많은 다른 프로젝트에서 사용하는 작은 모듈이 작성한 Readline NPM 내가 linebyline 나의 모듈을 게시 있도록 고유의 readline 모듈이 노드 V10의 참고 어떤것을 https://www.npmjs.com/package/을 linebyline
모듈을 사용하지 않으려면 기능이 매우 간단합니다.
var fs = require('fs'),
EventEmitter = require('events').EventEmitter,
util = require('util'),
newlines = [
13, // \r
10 // \n
];
var readLine = module.exports = function(file, opts) {
if (!(this instanceof readLine)) return new readLine(file);
EventEmitter.call(this);
opts = opts || {};
var self = this,
line = [],
lineCount = 0,
emit = function(line, count) {
self.emit('line', new Buffer(line).toString(), count);
};
this.input = fs.createReadStream(file);
this.input.on('open', function(fd) {
self.emit('open', fd);
})
.on('data', function(data) {
for (var i = 0; i < data.length; i++) {
if (0 <= newlines.indexOf(data[i])) { // Newline char was found.
lineCount++;
if (line.length) emit(line, lineCount);
line = []; // Empty buffer.
} else {
line.push(data[i]); // Buffer new line data.
}
}
}).on('error', function(err) {
self.emit('error', err);
}).on('end', function() {
// Emit last line if anything left over since EOF won't trigger it.
if (line.length){
lineCount++;
emit(line, lineCount);
}
self.emit('end');
}).on('close', function() {
self.emit('close');
});
};
util.inherits(readLine, EventEmitter);
또 다른 해결책은 순차적 실행기 nsynjs 를 통해 로직을 실행하는 것 입니다. 노드 readline 모듈을 사용하여 파일을 한 줄씩 읽으며 약속 또는 재귀를 사용하지 않으므로 큰 파일에서 실패하지 않습니다. 코드는 다음과 같습니다.
var nsynjs = require('nsynjs');
var textFile = require('./wrappers/nodeReadline').textFile; // this file is part of nsynjs
function process(textFile) {
var fh = new textFile();
fh.open('path/to/file');
var s;
while (typeof(s = fh.readLine(nsynjsCtx).data) != 'undefined')
console.log(s);
fh.close();
}
var ctx = nsynjs.run(process,{},textFile,function () {
console.log('done');
});
위 코드는이 시험을 기반으로합니다 : https://github.com/amaksr/nsynjs/blob/master/examples/node-readline/index.js
나는 이것을 사용한다 :
function emitLines(stream, re){
re = re && /\n/;
var buffer = '';
stream.on('data', stream_data);
stream.on('end', stream_end);
function stream_data(data){
buffer += data;
flush();
}//stream_data
function stream_end(){
if(buffer) stream.emmit('line', buffer);
}//stream_end
function flush(){
var re = /\n/;
var match;
while(match = re.exec(buffer)){
var index = match.index + match[0].length;
stream.emit('line', buffer.substring(0, index));
buffer = buffer.substring(index);
re.lastIndex = 0;
}
}//flush
}//emitLines
스트림에서이 기능을 사용하고 방출 될 회선 이벤트를 청취하십시오.
gr-
readline
최상위 답변에서 제안하는 것처럼 모듈을 사용해야하지만 readline
라인 읽기보다는 명령 줄 인터페이스를 지향하는 것으로 보입니다. 버퍼링과 관련하여 조금 더 불투명합니다. 스트리밍 라인 지향 리더가 필요한 사람은 아마도 버퍼 크기를 조정하고 싶을 것입니다. readline 모듈은 ~ 1000 줄이며 통계와 테스트는 34입니다.
const EventEmitter = require('events').EventEmitter;
class LineReader extends EventEmitter{
constructor(f, delim='\n'){
super();
this.totalChars = 0;
this.totalLines = 0;
this.leftover = '';
f.on('data', (chunk)=>{
this.totalChars += chunk.length;
let lines = chunk.split(delim);
if (lines.length === 1){
this.leftover += chunk;
return;
}
lines[0] = this.leftover + lines[0];
this.leftover = lines[lines.length-1];
if (this.leftover) lines.pop();
this.totalLines += lines.length;
for (let l of lines) this.onLine(l);
});
// f.on('error', ()=>{});
f.on('end', ()=>{console.log('chars', this.totalChars, 'lines', this.totalLines)});
}
onLine(l){
this.emit('line', l);
}
}
//Command line test
const f = require('fs').createReadStream(process.argv[2], 'utf8');
const delim = process.argv[3];
const lineReader = new LineReader(f, delim);
lineReader.on('line', (line)=> console.log(line));
통계가없는 19 줄의 더 짧은 버전은 다음과 같습니다.
class LineReader extends require('events').EventEmitter{
constructor(f, delim='\n'){
super();
this.leftover = '';
f.on('data', (chunk)=>{
let lines = chunk.split(delim);
if (lines.length === 1){
this.leftover += chunk;
return;
}
lines[0] = this.leftover + lines[0];
this.leftover = lines[lines.length-1];
if (this.leftover)
lines.pop();
for (let l of lines)
this.emit('line', l);
});
}
}
const fs = require("fs")
fs.readFile('./file', 'utf-8', (err, data) => {
var innerContent;
console.log("Asynchronous read: " + data.toString());
const lines = data.toString().split('\n')
for (let line of lines)
innerContent += line + '<br>';
});
일일 라인 처리의 전체 논리를 npm 모듈로 포장합니다. line-kit https://www.npmjs.com/package/line-kit
// example
var count = 0
require('line-kit')(require('fs').createReadStream('/etc/issue'),
(line) => { count++; },
() => {console.log(`seen ${count} lines`)})
아래 코드는 디렉토리가 아니며 파일 목록에 포함되어 있지 않은지 확인한 후 확인 행을 사용합니다.
(function () {
var fs = require('fs');
var glob = require('glob-fs')();
var path = require('path');
var result = 0;
var exclude = ['LICENSE',
path.join('e2e', 'util', 'db-ca', 'someother-file'),
path.join('src', 'favicon.ico')];
var files = [];
files = glob.readdirSync('**');
var allFiles = [];
var patternString = [
'trade',
'order',
'market',
'securities'
];
files.map((file) => {
try {
if (!fs.lstatSync(file).isDirectory() && exclude.indexOf(file) === -1) {
fs.readFileSync(file).toString().split(/\r?\n/).forEach(function(line){
patternString.map((pattern) => {
if (line.indexOf(pattern) !== -1) {
console.log(file + ' contain `' + pattern + '` in in line "' + line +'";');
result = 1;
}
});
});
}
} catch (e) {
console.log('Error:', e.stack);
}
});
process.exit(result);
})();
위의 모든 답변을 살펴본 결과 모두 타사 라이브러리를 사용하여 해결했습니다. Node의 API에는 간단한 솔루션이 있습니다. 예 :
const fs= require('fs')
let stream = fs.createReadStream('<filename>', { autoClose: true })
stream.on('data', chunk => {
let row = chunk.toString('ascii')
}))
참고 URL : https://stackoverflow.com/questions/6156501/read-a-file-one-line-at-a-time-in-node-js
'Programming' 카테고리의 다른 글
JavaScript에서 "double tilde"(~~) 연산자 란 무엇입니까? (0) | 2020.02.11 |
---|---|
cURL이 진행률 표시 줄을 표시하지 않게하려면 어떻게합니까? (0) | 2020.02.11 |
PowerShell에서 문자열과 변수를 어떻게 연결합니까? (0) | 2020.02.11 |
argparse를 사용하여 부울 값 구문 분석 (0) | 2020.02.11 |
Git의 사인 오프 기능은 무엇입니까? (0) | 2020.02.11 |