2012-09-17 4 views
17

큰 텍스트 파일을 가지고 있는데, 범위는 30MB10GB입니다. Node.js을 사용하여 파일의 줄 수를 계산하려면 어떻게합니까?Node.js : 파일의 줄 수를 계산하십시오.

  • 는 전체 파일을 자식 프로세스가 당신으로이 작업을 수행 할 수
+5

'wc -l file' ... – zerkms

+0

"NodeJS를 사용하여"-이 요구 사항의 실질적인 기술적 이유는 무엇입니까? – zerkms

+2

''wc'가 어떤 "네이티브"nodejs 솔루션보다 빠를 것이라고 확신합니다. – zerkms

답변

22

우리없이 솔루션 보내고 화장실 :

var i; 
var count = 0; 
require('fs').createReadStream(process.argv[2]) 
    .on('data', function(chunk) { 
    for (i=0; i < chunk.length; ++i) 
     if (chunk[i] == 10) count++; 
    }) 
    .on('end', function() { 
    console.log(count); 
    }); 

은 느리게,하지만 그 정도는 예상 - Node.js를 로딩 & 시작 시간을 포함하여 140M + 파일 0.6s

iojs 1.5.0 이후
>time node countlines.js video.mp4 
619643 

real 0m0.614s 
user 0m0.489s 
sys 0m0.132s 

>time wc -l video.mp4 
619643 video.mp4 
real 0m0.133s 
user 0m0.108s 
sys 0m0.024s 

>wc -c video.mp4 
144681406 video.mp4 
+3

벤치 마크는 선으로 구조화되지 않은 파일에서 실행하고 있으므로 OP가 처리하려고하는 파일 종류를 나타내지 않으므로 그다지 납득이 가지 않습니다. 'if (chunk [i] == 10) count ++;'라인은 바이너리 비디오 파일을 분석하는 것보다 텍스트 파일을 분석하는 동안 훨씬 더 자주 실행됩니다. – ebohlman

+0

100mb의 텍스트 파일이 없다 :) 그리고 유사한 100mb 텍스트 파일의 경우에도 줄 바꿈의 수는 10 배다. 모든 버퍼 덩어리의 모든 바이트를 반복하는 똑같은 선형 검색이다. –

+0

나는 복제했다. 입력 스크립트 자체를 단일 텍스트 파일 인 1468750000 문자, 62500000 행에 연결합니다. WC 시간 : 0m1.375s, node.js 시간 : 0m6.254s. 동일한 4.5 배 차이 (더 좋을 수도 있지만 JS 대 C 프로그램의 경우에는 여전히 충분 함) –

17

작업을 수행 할 필요가 없습니다

  • 메모리에 기록 할 필요가 없습니다 :

    나는이 제한이 의견을 사용하는 것이 좋습니다 wc

    var exec = require('child_process').exec; 
    
    exec('wc /path/to/file', function (error, results) { 
        console.log(results); 
    }); 
    
  • +10

    'wc'는 bash 특정 명령이며 windows 환경에서 작동하지 않을 수도 있습니다. 예를 들어 – Renaud

    +1

    'wc -l'은 행의 수를 계산합니다. –

    +1

    'wc -l path/to/file'은 filename과 함께 줄 수를 지정하십시오. 'wc -l Sarita

    1

    Buffer#indexOf() 방법이있다 Andrey Sidorov와 비교하기 위해 그것을 사용하여 '대답 :

    [email protected]:~$ wc logs 
        7342500 27548750 427155000 logs 
    [email protected]:~$ time wc -l logs 
    7342500 logs 
    
    real 0m0.180s 
    user 0m0.088s 
    sys 0m0.084s 
    [email protected]:~$ nvm use node 
    Now using node v0.12.1 
    [email protected]:~$ time node countlines.js logs 
    7342500 
    
    real 0m2.559s 
    user 0m2.200s 
    sys 0m0.340s 
    [email protected]:~$ nvm use iojs 
    Now using node iojs-v1.6.2 
    [email protected]:~$ time iojs countlines2.js logs 
    7342500 
    
    real 0m1.363s 
    user 0m0.920s 
    sys 0m0.424s 
    [email protected]:~$ cat countlines.js 
    var i; 
    var count = 0; 
    require('fs').createReadStream(process.argv[2]) 
        .on('data', function(chunk) { 
        for (i=0; i < chunk.length; ++i) 
         if (chunk[i] == 10) count++; 
        }) 
        .on('end', function() { 
        console.log(count); 
        }); 
    [email protected]:~$ cat countlines2.js 
    var i; 
    var count = 0; 
    require('fs').createReadStream(process.argv[2]) 
        .on('data', function(chunk) { 
        var index = -1; 
        while((index = chunk.indexOf(10, index + 1)) > -1) count++ 
        }) 
        .on('end', function() { 
        console.log(count); 
        }); 
    [email protected]:~$ 
    
    3

    여기에 많이 중첩하지 않고 다른 방법입니다.

    var fs = require('fs'); 
    filePath = process.argv[2]; 
    fileBuffer = fs.readFileSync(filePath); 
    to_string = fileBuffer.toString(); 
    split_lines = to_string.split("\n"); 
    console.log(split_lines.length-1); 
    
    +0

    10gb 파일의 경우, 말로만하면됩니다. –

    1

    또한 같이 IndexOf()를 사용할 수 있습니다

    var index = -1; 
    var count = 0; 
    while ((index = chunk.indexOf(10, index + 1)) > -1) count++; 
    
    3
    var fs=require('fs'); 
    filename=process.argv[2]; 
    var data=fs.readFileSync(filename); 
    var res=data.toString().split('\n').length; 
    console.log(res-1);` 
    
    +1

    이 코드 단편은 질문을 해결할 수 있지만 [설명 포함] (https://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers)은 게시물의 품질을 향상시키는 데 정말로 도움이됩니다. 앞으로 독자의 질문에 답하고 있으며 코드 제안의 이유를 알지 못할 수도 있습니다. 또한 주석을 설명하기 위해 코드를 군중시키지 마십시오. 그러면 코드와 설명 모두 가독성이 떨어집니다! –

    +0

    이 솔루션을 사용하려면 파일을 메모리에로드해야합니다. 나는 그것을 반대 할 것이다. 'wc'를 사용하는 대답은'wc'가 파일을 스트리밍하기 위해 최적화 되었기 때문에 아닙니다. –

    +0

    해답은 1 년 전에 똑같은 것을 게시 한 [Alan Viars] (https://stackoverflow.com/a/32286822/238978)에 비해 가치있는 것을 추가하지 않습니다. –

    1

    count-lines-in-file라는 NPM 모듈이있다. 난 작은 (< 1000 라인) 파일을 위해 그것을 사용 해왔고 지금까지 훌륭하게 작동했다.

    3

    우리는 VM이 ​​줄 바꿈을 찾을 수 indexOf를 사용할 수 있습니다

    function countFileLines(filePath){ 
        return new Promise((resolve, reject) => { 
        let lineCount = 0; 
        fs.createReadStream(filePath) 
        .on("data", (buffer) => { 
         let idx = -1; 
         lineCount--; // Because the loop will run once for idx=-1 
         do { 
         idx = buffer.indexOf(10, idx+1); 
         lineCount++; 
         } while (idx !== -1); 
        }).on("end",() => { 
         resolve(lineCount); 
        }).on("error", reject); 
        }); 
    }; 
    

    무엇이 솔루션이하는 것은 .indexOf를 사용하여 첫 번째 줄 바꿈의 위치를 ​​발견 한 것입니다. lineCount을 증가시키고 다음 위치를 찾습니다. .indexOf의 두 번째 매개 변수는 개행을 시작할 위치를 알려줍니다. 이렇게하면 버퍼의 큰 덩어리를 뛰어 넘고 있습니다. while 루프는 모든 개행마다 한 번 더 실행됩니다.

    우리는 노드 런타임이 하위 수준에서 구현되고 더 빨라야하는 우리를 검색하도록합니다.

    내 시스템에서는 큰 파일 (111MB)의 버퍼 길이를 초과하여 for 루프를 실행하는 것보다 약 두 배 빠릅니다.

    +1

    다른 솔루션과 비교해 볼 때이 솔루션이 가장 좋습니다! – loretoparisi

    관련 문제