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




file-io lazy-evaluation (17)

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

 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 की तरह कुछ उपयोग करने के लिए वापस आ सकता था, लेकिन मैं इसे समझना चाहता हूं।

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


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

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


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

एक और समाधान अनुक्रमिक निष्पादक 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


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

  });
});

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

const fs = require("fs")

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

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

मेरे पास एक छोटा सा मॉड्यूल है जो यह अच्छी तरह से करता है और कुछ अन्य परियोजनाओं द्वारा उपयोग किया जाता है एनपीएम रीडलाइन नोट नोड 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);

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

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

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


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

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

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


मैं इसी समस्या से निपटना चाहता था, मूल रूप से पर्ल में क्या होगा:

while (<>) {
    process_line($_);
}

मेरा उपयोग मामला सिर्फ एक स्टैंडअलोन स्क्रिप्ट था, सर्वर नहीं, इसलिए सिंक्रोनस ठीक था। ये मेरे मानदंड थे:

  • न्यूनतम सिंक्रोनस कोड जो कई परियोजनाओं में पुन: उपयोग कर सकता है।
  • फ़ाइल आकार या लाइनों की संख्या पर कोई सीमा नहीं है।
  • लाइनों की लंबाई पर कोई सीमा नहीं है।
  • बीएमपी से परे पात्रों सहित यूटीएफ -8 में पूर्ण यूनिकोड को संभालने में सक्षम।
  • * निक्स और विंडोज लाइन के अंतराल को संभालने में सक्षम (पुरानी शैली मैक मेरे लिए आवश्यक नहीं है)।
  • रेखा अंतराल चरित्रों को लाइनों में शामिल किया जाना चाहिए।
  • अंतराल के पात्रों के साथ या बिना अंतिम पंक्ति को संभालने में सक्षम।
  • Node.js वितरण में शामिल नहीं बाहरी पुस्तकालयों का उपयोग न करें।

यह मेरे लिए एक परियोजना है जो मुझे निम्न स्तर के स्क्रिप्टिंग प्रकार कोड के लिए node.js में महसूस करने के लिए एक प्रोजेक्ट है और यह तय करता है कि यह पर्ल जैसे अन्य स्क्रिप्टिंग भाषाओं के प्रतिस्थापन के रूप में कितना व्यवहार्य है।

एक आश्चर्यजनक मात्रा में प्रयास और कुछ झूठे शुरू होने के बाद यह कोड मैं आया था। यह बहुत तेज है लेकिन अपेक्षाकृत कम तुच्छ है: (गिटहब पर इसे कांटा)

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

इसे शायद आगे साफ किया जा सकता है, यह परीक्षण और त्रुटि का परिणाम था।


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

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

})();

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

const fs= require('fs')

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

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

लाइन लाइन फ़ाइल को पढ़ने के लिए एक बहुत अच्छा मॉड्यूल है, इसे 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);
    });
  }
});

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

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

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

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


});

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("++++++++++++++++++++")
})

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

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

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







lazy-evaluation