नोड.जेएस में एक समय में एक फ़ाइल एक पंक्ति पढ़ें?


551

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

 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 जैसी किसी चीज़ का उपयोग करके वापस गिर सकता हूं, लेकिन मैं यह पता लगाना चाहूंगा।

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


2
यह सिर्फ निम्न-स्तर का उपयोग करके काफी कठिन हो जाता है fs.readSync()। आप बाइनरी ऑक्टेट को एक बफर में पढ़ सकते हैं, लेकिन आंशिक रूप से UTF-8 या UTF-16 वर्णों से निपटने का कोई आसान तरीका नहीं है, बिना बफर का निरीक्षण किए इसे जावास्क्रिप्ट स्ट्रिंग्स में अनुवाद करने और EOLs के लिए स्कैन करने से पहले। इस Buffer()प्रकार के कार्यों में रिच स्ट्रिंग्स के रूप में देशी स्ट्रिंग्स के रूप में संचालित करने के लिए समृद्ध सेट नहीं है, लेकिन देशी स्ट्रिंग्स में बाइनरी डेटा नहीं हो सकता है। यह मुझे लगता है कि मनमाने ढंग से फाइलहैंडल्स से पाठ लाइनों को पढ़ने के लिए बिल्ट-इन तरीके का अभाव नोड में एक वास्तविक अंतर है।
हिप्पिट्रैयल

5
इस विधि से पढ़ी गई खाली रेखाएँ एक एकल 0 (वास्तविक वर्ण कोड 0) वाली रेखा में परिवर्तित हो जाती हैं। मुझे इस लाइन को वहां हैक करना था:if (line.length==1 && line[0] == 48) special(line);
Thabo

2
एक 'लाइन-बाय-लाइन' पैकेज का भी उपयोग कर सकता है जो पूरी तरह से काम करता है।
पैट्रिस

1
कृपया प्रश्न को यह कहने के लिए अपडेट करें कि समाधान एक परिवर्तन धारा
गेब्रियल लामास

2
@DanDascalescu यदि आप चाहें, तो आप इसे सूची में जोड़ सकते हैं: आपका उदाहरण node's एपीआई डॉक्स github.com/nodejs/node/pull/4609
eljefedelrodeeljefe

जवाबों:


787

चूंकि Node.js v0.12 और Node.js v4.0.0 के रूप में, एक स्थिर रीडलाइन कोर मॉड्यूल है। यहां किसी भी बाहरी मॉड्यूल के बिना, फ़ाइल से लाइनों को पढ़ने का सबसे आसान तरीका है:

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

या वैकल्पिक रूप से:

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

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


7
आपको एक टर्मिनल की आवश्यकता है: createInterface परिभाषा में गलत
Glasspill

64
अंतिम पंक्ति कैसे निर्धारित करें? "करीब" घटना को पकड़कर:rl.on('close', cb)
ग्रीन '

27
रीडलाइन GNU Readline के समान उद्देश्य के लिए है , लाइन द्वारा फ़ाइलों को पढ़ने के लिए नहीं । फ़ाइलों को पढ़ने के लिए इसका उपयोग करने में कई चेतावनी हैं और यह एक सर्वोत्तम अभ्यास नहीं है।
नेकेडबल

8
@ उल्लेखनीय: दिलचस्प। क्या आप बेहतर विधि के साथ उत्तर दे सकते हैं?
Dan Dascalescu

6
मुझे लगता है कि github.com/jahewson/node-byline लाइन-बाय-लाइन पढ़ने का सबसे अच्छा कार्यान्वयन है, लेकिन राय भिन्न हो सकती है।
नाकाबिल

164

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

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

33
दुख की बात है कि यह आकर्षक समाधान सही ढंग से काम नहीं करता है- lineईवेंट हिट होने के बाद ही आते हैं \n, यानी सभी विकल्प छूट जाते हैं (देखें unicode.org/reports/tr18/#Line_Boundaries )। # 2, आखिरी के बाद के आंकड़ों \nको चुपचाप नजरअंदाज कर दिया जाता है (देखें stackoverflow.com/questions/18450197/… )। मैं इस समाधान को खतरनाक कहूंगा क्योंकि यह सभी फ़ाइलों के 99% और डेटा के 99% के लिए काम करता है, लेकिन बाकी के लिए चुपचाप विफल रहता है । जब भी आप ऐसा करते हैं fs.writeFileSync( path, lines.join('\n'))तो आपने एक फ़ाइल लिखी है जो केवल उपरोक्त समाधान द्वारा आंशिक रूप से पढ़ी जाएगी।
प्रवाह करें

4
इस समाधान के साथ एक समस्या है। यदि आप अपने .js <lines.txt का उपयोग करते हैं तो आपको अंतिम पंक्ति नहीं मिलती है। यदि यह पाठ्यक्रम के अंत में एक '\ n' नहीं है।
zag2art

readlineएक अनुभवी यूनिक्स / लिनक्स प्रोग्रामर करने के लिए सही मायने में विचित्र तरीकों से पैकेज बर्ताव करती है।
नुकीले

11
rd.on("close", ..);एक कॉलबैक के रूप में इस्तेमाल किया जा सकता है (जब सभी लाइनें पढ़ी जाती हैं)
लुका स्टील

6
"अंतिम \ n" समस्या के बाद का डेटा मेरे नोड (0.12.7) संस्करण में हल किया जा रहा है। इसलिए मैं इस उत्तर को पसंद करता हूं, जो सबसे सरल और सबसे सुंदर लगता है।
Myk Melez

63

आप openफ़ाइल के लिए नहीं है , लेकिन इसके बजाय, आप एक बनाने के लिए है ReadStream

fs.createReadStream

फिर उस स्ट्रीम को पास करें Lazy


2
क्या आलसी के लिए एक अंतिम घटना की तरह कुछ है? जब सभी लाइनों में पढ़ा गया है?
अधिकतम

1
@Max, का प्रयास करें:new lazy(fs.createReadStream('...')).lines.forEach(function(l) { /* ... */ }).join(function() { /* Done */ })
Cecchi

6
@Cecchi और @Max, जुड़ने का उपयोग न करें क्योंकि यह पूरी फ़ाइल को मेमोरी में बफर कर देगा। इसके बजाय, बस 'अंत' की घटना को सुनिए:new lazy(...).lines.forEach(...).on('end', function() {...})
कोरिन

3
@Cecchi, @Corin, और @Max: इसके लायक क्या है, मैंने .on('end'... बाद में खुद को पागल कर दिया .forEach(...), जब वास्तव में जब मैंने पहले घटना को अंजाम दिया था , तब सब कुछ अपेक्षित था ।
क्राउनजो

52
खोज परिणामों पर यह परिणाम बहुत अधिक है, इसलिए यह ध्यान देने योग्य है कि आलसी को छोड़ दिया गया है। बिना किसी बदलाव के 7 महीने हो गए हैं, और कुछ भयावह कीड़े हैं (अंतिम पंक्ति को अनदेखा किया गया है, बड़े पैमाने पर मेमोरी लीक, आदि)।
ब्लू

38

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

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

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

4
यह अच्छा काम करता है। यह अंतिम पंक्ति (!) भी पढ़ता है। यह ध्यान देने योग्य है कि अगर यह विंडोज़ शैली की टेक्स्ट फ़ाइल है तो यह \ r को बनाए रखता है। line.trim () अतिरिक्त \ r को हटाने की कोशिश करता है।
पियरे-ल्यूक बर्ट्रेंड

यह उस इनपुट में उप-इष्टतम है जो केवल एक नामित फ़ाइल से हो सकता है, और नहीं (स्पष्ट और अत्यंत महत्वपूर्ण उदाहरण के लिए process/stdin)। कम से कम, यदि यह हो सकता है, तो यह निश्चित रूप से कोड को पढ़ने और इसे प्रयास करने से स्पष्ट नहीं है।
२०:१४

2
इस बीच में readlineकोर मॉड्यूल का उपयोग करके एक फ़ाइल से लाइनों को पढ़ने का एक अंतर्निहित तरीका है ।
डैन डेस्केल्सस्क्यू

यह पुराना है, लेकिन अगर कोई इस पर ठोकर खाए: function(reader)और function(line)होना चाहिए: function(err,reader)और function(err,line)
जालोर

1
सिर्फ रिकॉर्ड के लिए, line-readerफाइल को एसिंक्रोनसली पढ़ता है। इसका पर्यायवाची पर्याय हैline-reader-sync
प्रज्वल धतवालिया

30
require('fs').readFileSync('file.txt', 'utf-8').split(/\r?\n/).forEach(function(line){
  console.log(line);
})

42
यह पूरी फाइल को मेमोरी में पढ़ेगा , फिर इसे लाइनों में विभाजित करेगा। यह वह नहीं है जो सवाल पूछता है। मांग पर, क्रमिक रूप से बड़ी फ़ाइलों को पढ़ने में सक्षम होने के लिए बिंदु है।
डैनस्केलस्कु

2
यह मेरे उपयोग के मामले में फिट बैठता है, मैं इनपुट को एक स्क्रिप्ट से दूसरे प्रारूप में बदलने का एक सरल तरीका ढूंढ रहा था। धन्यवाद!
15

23

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

यह उत्तर अपने वादा-आधारित व्यवहार के लिए धन्यवाद से कहीं अधिक बेहतर है, जो ईओएफ को स्पष्ट रूप से इंगित करता है।
दर्शन

धन्यवाद, यह मीठा है।
गोरान स्टॉयनोव

3
शायद यह दूसरों के लिए स्पष्ट है, लेकिन मुझे डिबग करने में थोड़ा समय लगा: यदि आपके पास कॉल और लूप की शुरुआत के awaitबीच कोई एस है , तो आप फ़ाइल की शुरुआत से रहस्यमय तरीके से लाइनें खो देंगे। तुरंत दृश्यों के पीछे लाइनों को छोड़ना शुरू कर देता है, और इसके साथ बनाया गया async इट्रेटर उन लाइनों के लिए सुनना शुरू नहीं कर सकता है जब तक कि इसे बनाया नहीं जाता है। createInterface()for awaitcreateInterface()const line of rl
andrewdotn

19

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

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

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


2
यदि आप इसे प्राप्त करते हैं , readline is not definedया fs is not definedजोड़ते हैं var readline = require('readline');और var fs = require('fs');इसे काम करने के लिए प्राप्त करते हैं। अन्यथा मीठा, मीठा कोड। धन्यवाद।
bergie3000

12
यह उत्तर पहले के उत्तर का सटीक विवरण है , लेकिन टिप्पणियों के बिना रीडलाइन पैकेज को चेतावनी देते हुए अस्थिर (अभी भी अप्रैल 2015 के रूप में अस्थिर है) चिह्नित किया गया है, और 2013 के मध्य में, लाइन अंत के बिना एक फ़ाइल के अंतिम पंक्तियों को पढ़ने में परेशानी हुई थी । पिछली पंक्ति का मुद्दा पहली बार जब मैंने इसे v0.10.35 में उपयोग किया था, और फिर चला गया। / argh
रफिन

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

18

आप हमेशा अपने स्वयं के लाइन रीडर को रोल कर सकते हैं। मैंने अभी तक इस स्निपेट को बेंचमार्क नहीं किया है, लेकिन यह सही ढंग से अनुगामी धारा को '' एन '' के बिना लाइनों में विभाजित करता है।

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

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

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


stdinजब तक मैं किसी दिन याद नहीं कर रहा हूं, तब तक मनमानी फाइलों के साथ काम करने के लिए इसे बढ़ाने के लिए कोई तुच्छ तरीका नहीं लगता है ।
हिप्पिट्रैइल

3
@ ह्पीपिट्रिल आप के ReadStreamसाथ बना सकते हैं fs.createReadStream('./myBigFile.csv')और इसके बजाय का उपयोग कर सकते हैंstdin
12

2
क्या प्रत्येक चंक को केवल पूर्ण पंक्तियों को शामिल करने की गारंटी है? क्या मल्टी-बाइट UTF-8 वर्णों को चंक सीमाओं पर विभाजित नहीं होने की गारंटी है?
हिप्पिएट्रेल

1
@hippietrail मुझे नहीं लगता कि इस कार्यान्वयन द्वारा मल्टीबाइट पात्रों को सही ढंग से संभाला जाता है। उसके लिए, पहले बफ़र्स को सही ढंग से स्ट्रिंग्स में बदलना चाहिए और दो बफ़र्स के बीच विभाजित होने वाले पात्रों पर नज़र रखना चाहिए। ठीक से ऐसा करने के लिए, व्यक्ति StringDecoder
Ernelli

इस बीच में readlineकोर मॉड्यूल का उपयोग करके एक फ़ाइल से लाइनों को पढ़ने का एक अंतर्निहित तरीका है ।
डैन डेस्केल्सस्क्यू

12

साथ वाहक मॉड्यूल :

var carrier = require('carrier');

process.stdin.resume();
carrier.carry(process.stdin, function(line) {
    console.log('got one line: ' + line);
});

अच्छा लगा। यह किसी भी इनपुट फ़ाइल के लिए भी काम करता है: var inStream = fs.createReadStream('input.txt', {flags:'r'}); लेकिन आपके सिंटैक्स का उपयोग करने के प्रलेखित विधि की तुलना में क्लीनर है। ():carrier.carry(inStream).on('line', function(line) { ...
ब्रेंट फॉस्ट

मालवाहक केवल संभाल \r\nऔर \nलाइन अंत लगता है । यदि आपको कभी भी OS X से पहले MacOS- शैली की परीक्षण फ़ाइलों से निपटने की आवश्यकता होती है, तो वे उपयोग करते हैं \rऔर वाहक इसे संभालता नहीं है। हैरानी की बात है कि अभी भी ऐसी फाइलें जंगली में तैर रही हैं। आपको यूनिकोड BOM (बाइट ऑर्डर मार्क) को स्पष्ट रूप से संभालने की आवश्यकता हो सकती है, इसका उपयोग एमएस विंडोज के प्रभाव क्षेत्र में पाठ फ़ाइलों की शुरुआत में किया जाता है।
हिप्पिट्रैसिल

इस बीच में readlineकोर मॉड्यूल का उपयोग करके एक फ़ाइल से लाइनों को पढ़ने का एक अंतर्निहित तरीका है ।
डैन डेस्केल्सस्क्यू

9

मैं एक बड़े पैमाने पर बड़े पैमाने पर स्मृति रिसाव के साथ लाइन का उपयोग करके पढ़ने के लिए समाप्त हो गया जब लाइन को पढ़ने के लिए कोशिश कर रहा था, तब उन लाइनों को संसाधित करने और नोड कार्यों में नाली / ठहराव / फिर से शुरू करने के तरीके के कारण उन्हें एक और धारा में लिखना (देखें: http: // सुरुचिपूर्णकोड .com / 2011/04/06 / लेने वाले-बच्चे-कदम-के साथ-नोड-जेएस-पंपिंग-डेटा-बीच-धाराओं / (मैं इस आदमी को प्यार करता हूं)। मैंने आलसी को ठीक से समझने के लिए पर्याप्त रूप से नहीं देखा है, लेकिन मैं अपने पढ़ने की धारा को आलसी से बाहर निकलने के बिना एक नाली के लिए अनुमति देने के लिए रोक नहीं सका।

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

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

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


इस बीच readlineकोर मॉड्यूल का उपयोग करके फ़ाइल से लाइनों को पढ़ने का एक बहुत सरल तरीका है ।
डेन डैस्कलेस्क्यू

हाँ। यही अब सही तरीका है। लेकिन यह 2011 से था। :)
j03m

8

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

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


बफ़रडियर के साथ आप लाइनें पढ़ सकते हैं।

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

1
इस बीच readlineकोर मॉड्यूल का उपयोग करके फ़ाइल से लाइनों को पढ़ने का एक बहुत सरल तरीका है ।
डेन डैस्कलेस्क्यू

7

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

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

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


6

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

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

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


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

मैं इसका परीक्षण करूंगा, लेकिन क्या आप मुझे बता सकते हैं, क्या यह गारंटी दी जाती है कि कभी भी मल्टीबैट पात्रों को नहीं तोड़ना चाहिए? (UTF-8 / UTF-16)
हिप्पिट्रैयल

2
@hippietrail: इसका उत्तर UTF-8 के लिए नहीं है, भले ही यह एक चरित्र स्ट्रीम के बजाय बाइट स्ट्रीम पर काम कर रहा हो। यह newlines (0x0a) पर टूट जाता है। UTF-8 में, मल्टीबाइट कैरेक्टर के सभी बाइट्स में उनका हाई-ऑर्डर बिट सेट होता है। इस प्रकार, कोई भी मल्टीबैट चरित्र एक एम्बेडेड न्यूलाइन या अन्य सामान्य ASCII वर्ण को शामिल नहीं कर सकता है। यूटीएफ -16 और यूटीएफ -32 हालांकि एक और मामला है।
जॉर्ज

@ जॉर्ज: मुझे लगता है कि हम एक-दूसरे को गलत समझते हैं। जैसा कि CR और LF दोनों ASCII रेंज के भीतर हैं और UTF-8 128 ASCII कैरेक्टर्स को अपरिवर्तित रखता है, न तो CR और LF कभी भी मल्टीबैट UTF-8 कैरेक्टर का हिस्सा हो सकते हैं। मैं जो पूछ रहा था कि क्या dataकॉल stream.on("data")कभी भी शुरू हो सकता है या केवल एक मल्टीबैट यूटीएफ -8 चरित्र के कुछ हिस्सों के साथ शुरू हो सकता है U+10D0, जैसे कि तीन बाइट्स से बना हैe1 83 90
हिप्पिएट्रेल

1
यह अभी भी "नई लाइन" बनाने से पहले पूरी फ़ाइल सामग्री को मेमोरी में लोड करता है। यह एक बार में एक पंक्ति को पढ़ता नहीं है, यह सभी लाइनों को लेता है और फिर "नई लाइन" बफर लंबाई के अनुसार उन्हें तोड़ता है। यह विधि एक स्ट्रीम बनाने के उद्देश्य को हरा देती है।
जस्टिन

इस बीच कोर मॉड्यूल का उपयोग करके फ़ाइल से लाइनों को पढ़ने का एक बहुत सरल तरीका हैreadline
डेन डैस्कलेस्क्यू

5

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

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

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

  • न्यूनतम तुल्यकालिक कोड जो कई परियोजनाओं में पुन: उपयोग कर सकता है।
  • फ़ाइल आकार या लाइनों की संख्या की कोई सीमा नहीं।
  • लाइनों की लंबाई पर कोई सीमा नहीं।
  • यूएमएफ -8 में पूर्ण यूनिकोड को संभालने में सक्षम, बीएमपी से परे पात्रों सहित।
  • संभाल करने में सक्षम * निक्स और विंडोज लाइन एंडिंग (पुरानी शैली मैक मेरे लिए आवश्यक नहीं है)।
  • लाइन एंडिंग्स वर्ण (एस) को लाइनों में शामिल किया जाना है।
  • अंतिम पंक्ति के साथ या बिना अंत वर्णों को संभालने में सक्षम।
  • नोड्स .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;
    }
  }
}

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


5

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

const fs = require("fs")

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

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

2

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

  });
});

2

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

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

आपके और कोफ्रसा के उत्तर में क्या अंतर है?
बफेलो

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

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

आशा है कि यह मदद करता है


1

मेरे पास एक छोटा मॉड्यूल है जो इसे अच्छी तरह से करता है और काफी कुछ अन्य प्रोजेक्ट्स द्वारा उपयोग किया जाता है npm readline नोड t10 में नोड v10 है एक देशी रीडलाइन मॉड्यूल है इसलिए मैंने अपने मॉड्यूल को लाइनबीलाइन https://www.npmjs.com/package/ के रूप में पुनर्प्रकाशित किया है पंक्ति दर पंक्ति

यदि आप मॉड्यूल का उपयोग नहीं करना चाहते हैं तो फ़ंक्शन बहुत सरल है:

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

1

एक और उपाय है कि क्रमिक निष्पादक 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


1

ऐसे ऑपरेशन करते समय हमें अपने आप से दो सवाल पूछने चाहिए:

  1. इसे निष्पादित करने के लिए किस मेमोरी की मात्रा का उपयोग किया जाता है?
  2. क्या मेमोरी की खपत फ़ाइल आकार के साथ बहुत अधिक बढ़ रही है?

समाधान की तरह require('fs').readFileSync()पूरी फ़ाइल को मेमोरी में लोड करता है। इसका मतलब है कि ऑपरेशन करने के लिए आवश्यक मेमोरी की मात्रा फ़ाइल के आकार के लगभग बराबर होगी। हमें इससे बड़ी किसी भी चीज के लिए बचना चाहिए50mbs

हम आसानी से ट्रैक कर सकते हैं फ़ंक्शन मंगलाचरण के बाद कोड की इन पंक्तियों को रखकर किसी फ़ंक्शन द्वारा उपयोग की जाने वाली मेमोरी मात्रा :

    const used = process.memoryUsage().heapUsed / 1024 / 1024;
    console.log(
      `The script uses approximately ${Math.round(used * 100) / 100} MB`
    );

अभी एक बड़ी फ़ाइल से विशेष लाइनों को पढ़ने का सबसे अच्छा तरीका नोड्स का उपयोग करना है रीडलाइन करना है । प्रलेखन के एक अद्भुत उदाहरण हैं

हालाँकि हमें इसे करने के लिए किसी भी तृतीय-पक्ष मॉड्यूल की आवश्यकता नहीं है। लेकिन, यदि आप एक एंटरप्राइज़ कोड लिख रहे हैं, तो आपको बहुत सारे किनारे के मामलों को संभालना होगा। मुझे एपिक फाइल स्टोरेज नामक एक बहुत हल्का मॉड्यूल लिखना था उन सभी मामलों को संभालने के लिए ।

एपिक फाइल स्टोरेज मॉड्यूल: https://www.npmjs.com/package/apickfs प्रलेखन: https://github.com/apickjs/apickFS#readme

उदाहरण फ़ाइल: https://1drv.ms/t/s -TkMCsWInsSZiGptXYAFjalXOpUx

उदाहरण: मॉड्यूल स्थापित करें

npm i apickfs
// import module
const apickFileStorage = require('apickfs');
//invoke readByLineNumbers() method
apickFileStorage
  .readByLineNumbers(path.join(__dirname), 'big.txt', [163845])
  .then(d => {
    console.log(d);
  })
  .catch(e => {
    console.log(e);
  });

इस विधि को 4 जीबी तक की सघन फाइलों के साथ सफलतापूर्वक परीक्षण किया गया था।

big.text एक घनी पाठ फ़ाइल है जिसमें 163,845 लाइनें हैं और यह 124 एमबी की है। इस फ़ाइल से 10 विभिन्न लाइनों को पढ़ने की स्क्रिप्ट लगभग 4.63 एमबी मेमोरी का ही उपयोग करती है। और यह JSON को ऑब्जेक्ट या Arrays पर मुफ़्त में पार्स करता है। 🥳 गजब !!

हम फ़ाइल की एक लाइन या फ़ाइल की सैकड़ों लाइनें बहुत कम मेमोरी खपत के साथ पढ़ सकते हैं।


0

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

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-


0

हालांकि आपको संभवतः 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);
        });
    }
}

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


});

0

मैं एक npm मॉड्यूल के रूप में दैनिक लाइन प्रसंस्करण के पूरे तर्क को लपेटता हूं: लाइन-किट 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`)})


-1

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

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

})();

-1

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

const fs= require('fs')

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

stream.on('data', chunk => {
    let row = chunk.toString('ascii')
}))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.