node.js: bir diziye bir metin dosyasını okuyun. (Her satır dizideki bir öğedir.)


165

Node.js'de bir JavaScript dizisine çok çok büyük bir dosya okumak istiyorum.

Eğer dosya böyle ise:

first line
two 
three
...
...

Ben dizi olurdu:

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

İşlev şöyle görünecektir:

var array = load(filename); 

Bu nedenle, hepsini bir dize olarak yükleme ve sonra bölme fikri kabul edilemez.


Bu sorunun ciddi bir şekilde düzenlenmesi ve temizlenmesi gerekiyor. Bir metin dosyasını bir diziye okuduğunu söyler , ancak tüm cevapları ve yorumları okuduğunuzda, bir seferde bir satır metin okumak anlamına gelir . Bu soru için @zswang şimdiye kadarki en iyi cevaba sahip.
Jess

yup sadece bu dosyayı okuyun ve her satırı bir diziye itin: stackoverflow.com/a/34033928/1536309
Blair Anderson

Yanıtlar:


89

Nihai verileri bir diziye sığdırabiliyorsanız, bir dizeye sığdıramaz ve önerildiği gibi bölebilir misiniz? Her durumda, dosyayı bir seferde bir satır işlemek isterseniz, bunun gibi bir şeyi de deneyebilirsiniz:

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

EDIT: ( phopkins tarafından yoruma yanıt olarak ) Bence (en azından yeni sürümlerinde) alt dize veri kopyalamaz ama özel bir SlicedString nesnesi oluşturur (v8 kaynak kodu hızlı bir bakıştan). Her durumda, bahsedilen alt dizeyi önleyen bir değişikliktir (bir dosyada birkaç megabayt değerinde "Tüm iş ve oyun yok, Jack'i sıkıcı bir çocuk yapar"):

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

Teşekkürler. sorunuzu cevaplamak için: hayır, dize çok büyük olurdu.
chacko

7
Ben yaklaşık 2MB ya da öylesine dosyalarda denedim ve acı bir yavaş, bir dize senkronize dosyaları okumak daha çok daha yavaş oldu. Sorunun kalan = kalan.substring hattı olduğunu düşünüyorum. Düğümün "verileri" her seferinde size çok şey verebilir ve bu kopyayı her satır için hızlıca yapmak O (n ^ 2) olur.
Fiona Hopkins


444

Senkron:

var fs = require('fs');
var array = fs.readFileSync('file.txt').toString().split("\n");
for(i in array) {
    console.log(array[i]);
}

Asenkron:

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
Teşekkürler. Maalesef sorumu düzenlemek zorunda kaldım. Yani büyük boyutlu bir dosyayı nasıl okuyacağım. Hepsini bir dizede okumak kabul edilemez.
chacko

1
Tam ihtiyacım olan şey. Basit ve hızlı.
Hcabnettek

16
Bunu Windows tarafından yapılmış bir dosyada buldum, bölmek zorunda kaldım \ r \ n ama bu Mac'leri kırdı; böylece daha sağlam; _array = string.replace (/ \ r \ n / g, '\ n'). bölünmüş ('\ n'); her ikisi için de çalıştı
Will Hancock

6
+1 Stackoverflow'da bir sorun var. Şimdi, çok aşağı kaydırdıktan sonra sıkça yüksek oy alan cevaplar buluyorum. Bu da bunun bir örneğidir. En yüksek oyu alır ancak sayfanın en altına yerleştirilir, son olarak. Stackoverflow'un sipariş algoritmalarını iyileştirmesi gerektiğini düşünüyorum.
shashwat

1
@shashwat Soruyu soran kişi hangisinin doğru cevap olduğuna karar verir. Bu durumda, büyük dosyalar için bir akış çözümüne ihtiyaçları vardı ve tüm dosyayı bir dizeye koymak kabul edilemez. Gerçekten SO ile yanlış bir şey yok.
yasallaştır

73

Node.js readline modülünü kullanma .

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
Ne yazık ki bu çözüm ile ilgili bir sorun var: Dosyanın \nsonunda bir yoksa son satırı almazsınız ! Bakınız: stackoverflow.com/questions/18450197/…
Yves M.


14

js:

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

ts:

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

1
Yukarıdakilerin atmasını önlemek için TypeError: fs.readFileSync(...).split is not a function.toString () yöntemini şu şekilde kullanmalısınız:var array = fs.readFileSync('file.txt', 'utf8').toString().split('\n');
Qua285

11

readline'ı ( dokümantasyon ) kullanın . İşte bir css dosyasını okuma, simgeleri ayrıştırma ve bunları json'a yazma örneği

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.linesile JFile paketiyle

Sözde

var JFile=require('jfile');

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

Daha önce unutma:

npm install jfile --save

5

Bir ile BufferedReader ancak fonksiyon asenkron olmalıdır:

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

Sadece @finbarr büyük cevap, asenkron örnekte küçük bir düzeltme eklemek istiyorum:

Asenkron:

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 () zaman uyumsuzluğunu serbest bırakan şeydir. aramak.


3

Bu, mtomis tarafından verilen cevapta bir varyasyon.

Bir çizgi akışı oluşturur. 'Veri' ve 'bitiş' olayları yayınlayarak akışın sonunu ele almanızı sağlar.

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;

Sarıcı olarak kullanın:

var lineInput = new LineStream(input);

lineInput.on('data', function (line) {
    // handle line
});

lineInput.on('end', function() {
    // wrap it up
});

1
Örnekler arasında paylaşılan etkinliklere sahip olursunuz. var EventEmitter = require('events').EventEmitter; var util = require('util'); function GoodEmitter() { EventEmitter.call(this); } util.inherits(GoodEmitter, EventEmitter);
CTAPbIu_MABP

Tam olarak hangi örneklerden bahsediyorsun?
oferei

1
oluşturmaya çalışın, var li1 = new LineStream(input1), li2 = new LineStream(input2);sonra her biri için kaç kez 'son' tetiklendiğini
sayın

denedim. 'son' her örnek için bir kez tetiklendi. 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'); }); output: metin dosyasındaki her satır, her örnek için bir kez tetiklendi. 'son'du.
oferei

2

Aynı problemi yaşadım ve modül ile satır satır çözdüm

https://www.npmjs.com/package/line-by-line

En azından benim için hem senkron hem de senkronize olmayan modda bir cazibe gibi çalışıyor.

Ayrıca, sonlanmayan satırların sonlanmasıyla ilgili sorun \ n şu seçenekle çözülebilir:

{ encoding: 'utf8', skipEmptyLines: false }

Hatların senkronize işlenmesi:

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 veya üstünü kullanmak, normal işlevi zaman uyumsuz bir işleve dönüştüren yeni bir özelliğe sahiptir.

util.promisify

Harika bir özellik. İşte txt dosyasından bir dizi içine 10000 sayı ayrıştırma ve sayılar üzerinde birleştirme sıralaması kullanarak ters çevirmeleri sayma örneği.

// 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

Büyük bir dosyayı diziye okumak için satır satır okuyabilir veya yığın yığın oluşturabilirsiniz.

satır satır cevabımı buraya bakın

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

yığın tarafından yığın bakın bu makalede

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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.