javascript Node.js में एक समय में एक फ़ाइल को एक पंक्ति पढ़ें?




file-io lazy-evaluation (20)

मैं एक समय में एक बड़ी फाइल को एक पंक्ति पढ़ने की कोशिश कर रहा हूं। मुझे क्वारा पर एक सवाल मिला जिसने इस विषय के साथ निपटाया लेकिन मुझे पूरी चीज एक साथ फिट करने के लिए कुछ कनेक्शन याद आ रहे हैं।

 var Lazy=require("lazy");
 new Lazy(process.stdin)
     .lines
     .forEach(
          function(line) { 
              console.log(line.toString()); 
          }
 );
 process.stdin.resume();

मैं जिस बिट को समझना चाहता हूं वह इस नमूने में एसटीडीआईएन की बजाय फ़ाइल से एक समय में एक पंक्ति को कैसे पढ़ सकता है।

मैंने कोशिश की:

 fs.open('./VeryBigFile.csv', 'r', '0666', Process);

 function Process(err, fd) {
    if (err) throw err;
    // DO lazy read 
 }

लेकिन यह काम नहीं कर रहा है। मुझे पता है कि एक चुटकी में मैं PHP की तरह कुछ उपयोग करने के लिए वापस आ सकता था, लेकिन मैं इसे समझना चाहता हूं।

मुझे नहीं लगता कि दूसरा जवाब काम करेगा क्योंकि फ़ाइल जिस सर्वर पर चल रहा है उससे कहीं अधिक बड़ी है।


ज्यादातर मामलों में यह पर्याप्त होना चाहिए:

const fs = require("fs")

fs.readFile('./file', 'utf-8', (err, file) => {
  const lines = file.split('\n')

  for (let line of lines)
    console.log(line)
});

जेनरेटर आधारित लाइन रीडर: 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());
    }

  });
});

संपादित करें:

एक ट्रांसफॉर्म स्ट्रीम का प्रयोग करें।

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

यदि आप लाइन द्वारा एक फ़ाइल लाइन पढ़ना चाहते हैं और इसे दूसरे में लिखना चाहते हैं:

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

मैं इसका उपयोग करता हूं:

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-


पुराना विषय, लेकिन यह काम करता है:

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

सरल। बाहरी मॉड्यूल की आवश्यकता नहीं है।


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>';


});

इस तरह के एक सरल ऑपरेशन के लिए तीसरे पक्ष के मॉड्यूल पर कोई निर्भरता नहीं होनी चाहिए। विनम्र रहो।

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

मैंने उपर्युक्त उत्तरों को देखा है, वे सभी इसे हल करने के लिए तीसरे पक्ष की लाइब्रेरी का उपयोग करते हैं। नोड के एपीआई में इसका एक आसान समाधान है। जैसे

const fs= require('fs')

let stream = fs.createReadStream('<filename>', { autoClose: true })

stream.on('data', chunk => {
    let row = chunk.toString('ascii')
}))


एक और समाधान अनुक्रमिक निष्पादक nsynjs माध्यम से तर्क चलाने के लिए है। यह नोड रीडलाइन मॉड्यूल का उपयोग करके फ़ाइल लाइन-बाय-लाइन पढ़ता है, और यह वादे या रिकर्सन का उपयोग नहीं करता है, इसलिए बड़ी फ़ाइलों पर असफल होने वाला नहीं है। यहां बताया गया है कि कोड कैसा दिखता है:

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


मैं इसके लिए एक व्यापक समाधान की कमी से निराश था, इसलिए मैंने अपना खुद का प्रयास ( git / npm ) रखा। सुविधाओं की प्रतिलिपि बनाई गई सूची:

  • इंटरेक्टिव लाइन प्रसंस्करण (कॉलबैक-आधारित, पूरी फ़ाइल को रैम में लोड नहीं किया जा रहा है)
  • वैकल्पिक रूप से, एक सरणी में सभी लाइनें लौटें (विस्तृत या कच्चे मोड)
  • स्ट्रीमिंग में इंटरैक्टिव रूप से बाधा डालें, या प्रोसेसिंग जैसे मानचित्र / फ़िल्टर करें
  • किसी भी न्यूलाइन सम्मेलन का पता लगाएं (पीसी / मैक / लिनक्स)
  • सही ईओएफ / अंतिम लाइन उपचार
  • बहु-बाइट यूटीएफ -8 अक्षरों का सही संचालन
  • प्रति पंक्ति आधार पर बाइट ऑफ़सेट और बाइट लंबाई की जानकारी पुनर्प्राप्त करें
  • लाइन-आधारित या बाइट-आधारित ऑफसेट का उपयोग करके यादृच्छिक पहुंच
  • यादृच्छिक अभिगम को गति देने के लिए स्वचालित रूप से लाइन-ऑफ़सेट जानकारी को मानचित्र करें
  • शून्य निर्भरताएं
  • टेस्ट

एनआईएच? आप तय करें :-)


आप हमेशा अपना खुद का लाइन रीडर रोल कर सकते हैं। मैंने अभी तक इस स्निपेट को बेंचमार्क नहीं किया है, लेकिन यह पिछली परतों के बिना लाइनों में आने वाली धाराओं को सही ढंग से विभाजित करता है '\ 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();

लॉग पेर्सिंग के दौरान डेटा जमा करने के लिए आवश्यक त्वरित लॉग पार्सिंग स्क्रिप्ट पर काम करते समय मैं इसके साथ आया था और मुझे लगा कि पेर्ल या बैश का उपयोग करने के बजाय जेएस और नोड का उपयोग करके ऐसा करने का प्रयास करना अच्छा लगेगा।

वैसे भी, मुझे लगता है कि छोटे नोडज स्क्रिप्ट को स्वयं निहित होना चाहिए और तीसरे पक्ष के मॉड्यूल पर भरोसा नहीं करना चाहिए, इसलिए इस प्रश्न के सभी उत्तरों को पढ़ने के बाद, प्रत्येक लाइन पार्सिंग को संभालने के लिए विभिन्न मॉड्यूल का उपयोग करके, 13 एसएलओसी देशी नोडजेस समाधान ब्याज का हो सकता है।


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

मुझे एक ही समस्या थी और उपर्युक्त समाधान के साथ आया दूसरों के लिए समान दिखता है लेकिन एक सिंक है और बड़ी फ़ाइलों को बहुत जल्दी पढ़ सकता है

उम्मीद है कि यह मदद करता है


लाइन लाइन फ़ाइल को पढ़ने के लिए एक बहुत अच्छा मॉड्यूल है, इसे line-reader कहा जाता है

इसके साथ आप बस लिखते हैं:

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

यदि आपको अधिक नियंत्रण की आवश्यकता है, तो आप फ़ाइल को "जावा-स्टाइल" इंटरफेस के साथ भी पुन: सक्रिय कर सकते हैं:

lineReader.open('file.txt', function(reader) {
  if (reader.hasNextLine()) {
    reader.nextLine(function(line) {
      console.log(line);
    });
  }
});

मेरे मूल उत्तर पोस्ट करने के बाद, मैंने पाया कि split फ़ाइल में पढ़ने के लिए नोड मॉड्यूल का उपयोग करना बहुत आसान है; जो वैकल्पिक पैरामीटर भी स्वीकार करता है।

var split = require('split');
fs.createReadStream(file)
    .pipe(split())
    .on('data', function (line) {
      //each chunk now is a seperate line! 
    });

बहुत बड़ी फाइलों पर परीक्षण नहीं किया है। अगर आप करते हैं तो हमें बताएं।


मैं उन लाइनों को संसाधित करने की कोशिश करते समय लाइन से लाइन पढ़ने के लिए आलसी का उपयोग करके भारी, भारी मेमोरी रिसाव के साथ समाप्त हुआ और नोड कार्यों में नाली / रोक / फिर से शुरू करने के तरीके के कारण उन्हें दूसरी स्ट्रीम में लिखना (देखें: http://elegantcode.com/2011/04/06/taking-baby-steps-with-node-js-pumping-data-between-streams/ (मुझे इस लड़के को प्यार है))। मैंने आलसी में वास्तव में क्यों समझने के लिए पर्याप्त रूप से पर्याप्त नहीं देखा है, लेकिन मैं अपनी पढ़ी धारा को रोका नहीं जा सकता था ताकि बिना आलसी निकलने के नाली की अनुमति मिल सके।

मैंने बड़े सीएसवी फाइलों को एक्सएमएल डॉक्स में संसाधित करने के लिए कोड लिखा है, आप यहां कोड देख सकते हैं: https://github.com/j03m/node-csv2xml

यदि आप आलसी रेखा के साथ पिछले संशोधन चलाते हैं तो यह लीक हो जाता है। नवीनतम संशोधन बिल्कुल रिसाव नहीं करता है और आप शायद इसे पाठक / प्रोसेसर के आधार के रूप में उपयोग कर सकते हैं। हालांकि मेरे पास कुछ कस्टम सामान हैं।

संपादित करें: मुझे लगता है कि मुझे यह भी ध्यान रखना चाहिए कि आलसी के साथ मेरा कोड ठीक काम करता है जब तक कि मैंने खुद को पर्याप्त बड़े एक्सएमएल टुकड़े लिखते हुए नहीं पाया जो एक आवश्यकता के कारण निकालें / रोकें / फिर से शुरू करें। छोटे टुकड़ों के लिए यह ठीक था।


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

अंतिम पंक्ति सही ढंग से पढ़ी जाती है (नोड v0.12 या बाद में), भले ही कोई अंतिम \n

अद्यतन : यह उदाहरण नोड के एपीआई आधिकारिक दस्तावेज में जोड़ा गया है।


मैं नीचे कोड का उपयोग यह सत्यापित करने के बाद करता हूं कि यह निर्देशिका नहीं है और फ़ाइलों की सूची में शामिल नहीं है, इसकी जांच की आवश्यकता नहीं है।

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

})();

जबकि आपको संभवतः 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));

आंकड़ों के बिना, 1 9 लाइनों पर, यहां तक ​​कि एक छोटा संस्करण भी है:

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




lazy-evaluation