node.js : 텍스트 파일을 배열로 읽습니다. (각 배열의 항목을 정렬합니다.)


164

node.js의 매우 큰 파일을 JavaScript 배열로 읽고 싶습니다.

따라서 파일이 다음과 같은 경우

first line
two 
three
...
...

나는 배열을 가질 것이다 :

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

함수는 다음과 같습니다.

var array = load(filename); 

따라서 모두 문자열로로드 한 다음 분할하는 아이디어는 허용되지 않습니다.


이 질문에는 약간의 편집과 정리가 필요합니다. 그것은 텍스트 파일을 배열로 읽는 다고 말하지만 , 모든 답변과 의견을 읽을 때 실제로 한 번에 한 줄씩 텍스트 파일을 읽는 것을 의미 합니다 . 그 질문에 대해 @zswang은 지금까지 가장 좋은 답변을 가지고 있습니다.
Jess

그래 그냥 파일을 읽고 배열로 각 행을 밀어 : stackoverflow.com/a/34033928/1536309
블레어 앤더슨

답변:


89

최종 데이터를 배열에 맞추면 제안 된 것처럼 문자열에 맞추고 나눌 수 없습니까? 어쨌든 한 번에 한 줄씩 파일을 처리하려면 다음과 같이 시도하십시오.

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 소스 코드를 한눈에). 어쨌든 여기에 언급 된 하위 문자열을 피하는 수정 사항이 있습니다 (파일에서 "모든 작업과 재생이 없으면 잭이 둔한 소년이됩니다").

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

감사. 귀하의 질문에 대답하기 위해 : 아니요, 문자열이 너무 큽니다.
chacko

7
약 2MB 정도의 파일 에서이 작업을 시도했으며 파일을 문자열로 동 기적으로 읽는 것보다 훨씬 느리게 느 렸습니다. 문제는 나머지 = 남아있는 하위 문자열 줄이라고 생각합니다. 노드의 "데이터"는 한 번에 많은 양을 제공 할 수 있으며 모든 줄에 대해 해당 사본을 작성하면 빠르게 O (n ^ 2)가됩니다.
Fiona Hopkins 2:18에


444

동기식 :

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

11
감사. 불행히도 내 질문을 편집해야했습니다. 대용량 파일을 읽는 방법을 의미합니다. 문자열로 모두 읽는 것은 허용되지 않습니다.
chacko

1
내가 필요한 것만 간단하고 빠릅니다.
Hcabnettek

16
Windows에서 만든 파일에서이 작업을 수행하는 것을 발견했습니다. \ r \ n을 분리해야했지만 Mac이 손상되었습니다. 더 강력합니다. _array = string.replace (/ \ r \ n / g, '\ n'). split ( '\ n'); 둘 다 일했다
Will Hancock

6
+1 Stackoverflow에 문제가 있습니다. 이제는 너무 아래로 스크롤 한 후 투표율이 높은 답변을 자주 찾습니다. 이것도 이것의 예입니다. 투표는 가장 높지만 페이지 하단에 배치됩니다. Stackoverflow는 순서 알고리즘을 개선해야한다고 생각합니다.
shashwat

1
@shashwat 질문을하는 사람은 누가 정답인지를 결정하게됩니다. 이 경우에는 큰 파일을위한 스트리밍 솔루션이 필요했으며 전체 파일을 문자열에 넣는 것은 허용되지 않습니다. 실제로 아무 문제가 없습니다.
합법화

73

Node.js readline 모듈 사용 .

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

1
슬프게도이 솔루션 에는 문제 가 있습니다. 파일 \n끝에 끝에 가 없으면 마지막 줄이 표시되지 않습니다 ! 참조 : stackoverflow.com/questions/18450197/...
이브 M.


14

js :

var array = fs.readFileSync('file.txt', 'utf8').split('\n');

TS :

var array = fs.readFileSync('file.txt', 'utf8').toString().split('\n');

1
위를 던지지 않게하려면 TypeError: fs.readFileSync(...).split is not a function.toString ()을 다음과 같이 사용해야합니다.var array = fs.readFileSync('file.txt', 'utf8').toString().split('\n');
Qua285

11

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

6

file.linesJFile 패키지

가짜

var JFile=require('jfile');

var myF=new JFile("./data.txt");
myF.lines // ["first line","second line"] ....

전에 잊지 마세요 :

npm install jfile --save

5

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

난 그냥 @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 ()은 비동기를 해제하는 것입니다. 요구.


3

이것은 @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
});

1
인스턴스간에 이벤트를 공유하는 것으로 끝납니다. var EventEmitter = require('events').EventEmitter; var util = require('util'); function GoodEmitter() { EventEmitter.call(this); } util.inherits(GoodEmitter, EventEmitter);
CTAPbIu_MABP

어떤 경우에 대해 정확히 이야기하고 있습니까?
oferei

1
만들려고 var li1 = new LineStream(input1), li2 = new LineStream(input2);항상 '끝'각각에 대해 해고 얼마나 많은 계산 후
CTAPbIu_MABP

그것을 시도했다. 각 인스턴스에 대해 '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'); }); 출력 : 텍스트 파일의 각 줄은 각 인스턴스마다 한 번씩 시작되었습니다. '끝'도 마찬가지였습니다.
oferei

2

나는 같은 문제가 있었고, 모듈별로 한 줄씩 해결했다.

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

2

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

1

큰 파일을 배열로 읽으려면 한 줄씩 또는 덩어리로 읽을 수 있습니다.

한 줄씩 내 대답을 참조 하십시오.

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

chunk by chunk 이 기사를 참조 하십시오

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);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.