Node.js dosyasında bir kerede bir satır mı okuyorsunuz?


553

Her seferinde bir satır büyük bir dosya okumaya çalışıyorum. Quora'da konuyla ilgilenen bir soru buldum , ancak her şeyi birbirine uydurmak için bazı bağlantıları kaçırıyorum.

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

Anlamak istediğim bit, bu örnekte olduğu gibi STDIN yerine bir dosyadan her seferinde bir satır nasıl okuyabileceğim.

Denedim:

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

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

ama işe yaramıyor. Ben bir tutam PHP gibi bir şey kullanarak geri düşebilir biliyorum, ama ben bunu anlamak istiyorum.

Dosya üzerinde çalıştığım sunucudan daha büyük olduğu için diğer yanıtın çalışacağını sanmıyorum.


2
Bu sadece düşük seviye kullanarak oldukça zor olduğu ortaya çıkıyor fs.readSync(). İkili sekizlileri bir arabellekte okuyabilirsiniz, ancak JavaScript dizelerine çevirmeden ve EOL'leri taramadan önce arabelleği incelemeden kısmi UTF-8 veya UTF-16 karakterleriyle başa çıkmanın kolay bir yolu yoktur. Buffer()Tip yerli dizileri olarak kendi örneklerinde çalışmasına fonksiyonların zengin set olarak sahip değil, ancak yerli dizeleri ikili veri içeremez. Bana öyle geliyor ki, keyfi dosya tanıtıcılarından metin satırlarını okumak için yerleşik bir yoldan yoksun, node.js'de gerçek bir boşluk.
hippietrail

5
Bu yöntemle okunan boş satırlar, içinde tek bir 0 (0 için gerçek karakter kodu) bulunan bir satıra dönüştürülür. Orada bu hattı kesmek zorunda kaldım:if (line.length==1 && line[0] == 48) special(line);
Thabo

2
İşi mükemmel yapan 'satır satır' paketi de kullanılabilir.
Patrice

1
Lütfen sorunun çözümün bir dönüşüm akışı
Gabriel Llamas

2
İsterseniz @DanDascalescu bunu listeye ekleyebilirsiniz: örneğinizin nodeAPI dokümanlarında hafifçe değiştirilmiş olarak gönderildi github.com/nodejs/node/pull/4609
eljefedelrodeodeljefe

Yanıtlar:


789

Node.js v0.12 yana ve node.js v4.0.0 itibarıyla stabil olduğu taleb çekirdek modülü. Harici modüller olmadan dosyadan satır okumanın en kolay yolu:

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

Veya alternatif olarak:

var lineReader = require('readline').createInterface({
  input: require('fs').createReadStream('file.in')
});

lineReader.on('line', function (line) {
  console.log('Line from file:', line);
});

Son satır olmasa bile, son satır doğru okunur (Düğüm v0.12 veya sonrası) \n.

GÜNCELLEME : bu örnek Düğüm API'sı resmi belgelerine eklenmiştir .


7
bir terminale ihtiyacınız var: createInterface tanımında false
glasspill

64
Son satır nasıl belirlenir? Bir "kapat" etkinliği yakalayarak:rl.on('close', cb)
Yeşil

27
Readline, dosyaları satır satır okumak için değil , GNU Readline ile benzer bir amaç içindir. Dosyaları okumak için kullanmanın birkaç uyarısı vardır ve bu en iyi uygulama değildir.
Nakedible

8
@Nakedible: ilginç. Daha iyi bir yöntemle yanıt gönderebilir misiniz?
Dan Dascalescu

6
Ben düşünün github.com/jahewson/node-byline hat-by-line okuma iyi bir uygulaması olarak, ancak görüşler değişebilir.
Nakedible

164

Bu kadar basit bir işlem için üçüncü taraf modüllere bağımlılık olmamalıdır. Sakin ol.

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
ne yazık ki, bu çekici çözüm düzgün çalışmıyor - lineolaylar sadece vurulduktan sonra geliyor \n, yani tüm alternatifler kaçırıldı (bkz. unicode.org/reports/tr18/#Line_Boundaries ). # 2, sonuncudan sonraki veriler \nsessizce göz ardı edilir (bkz. Stackoverflow.com/questions/18450197/… ). tüm dosyaları% 99 ve% 99 veri için çalışır ama geri kalanı için sessizce başarısız çünkü bu çözümü tehlikeli olarak adlandırır . ne zaman yaparsanız yapın yukarıdaki çözüm tarafından sadece kısmen okunacak bir dosya yazdınız. fs.writeFileSync( path, lines.join('\n'))
akış

4
Bu çözümle ilgili bir sorun var. ..Js <lines.txt dosyanızı kullanırsanız, son satırı almazsınız. Tabii ki sonunda '\ n' yoksa.
zag2art

readlineDeneyimli bir Unix / Linux programcısı gerçekten tuhaf şekillerde paket davranacağını.
Sivri

11
rd.on("close", ..);geri arama olarak kullanılabilir (tüm satırlar okunduğunda gerçekleşir)
Luca Steeb

6
Düğüm (0.12.7) sürümünde "son \ n sonra veri" sorunu giderilmiş gibi görünüyor. Bu yüzden en basit ve zarif görünen bu cevabı tercih ediyorum.
Myk Melez

63

Sen gerekmez opendosyası, ancak bunun yerine, bir oluşturmak zorunda ReadStream.

fs.createReadStream

Sonra bu akışı Lazy


2
Lazy için bir son etkinlik gibi bir şey var mı? Tüm satırlar ne zaman okundu?
Max

1
@Max, Dene:new lazy(fs.createReadStream('...')).lines.forEach(function(l) { /* ... */ }).join(function() { /* Done */ })
Cecchi

6
@Cecchi ve @Max, birleştirme kullanmayın çünkü tüm dosyayı bellekte arabelleğe alır. Bunun yerine, 'son' etkinliğini dinleyin:new lazy(...).lines.forEach(...).on('end', function() {...})
Corin

3
@Cecchi, @Corin ve @Max: Ne 's değerinde için, kendime deli zincirleme sürdü .on('end'... sonra .forEach(...) ben olayı bağlandığı zaman, aslında her şey beklendiği gibi davrandım zaman, ilk .
crowjonah

52
Bu sonuç arama sonuçlarında çok yüksektir, bu yüzden Lazy'nin terk edilmiş göründüğünü belirtmek gerekir. Herhangi bir değişiklik yapılmadan 7 ay oldu ve bazı korkunç hatalar var (son satır yok sayıldı, büyük bellek sızıntıları, vb.).
blu

38

bir dosyayı satır satır okumak için çok güzel bir modül var, buna satır okuyucu deniyor

onunla sadece yazmanız yeterlidir:

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

daha fazla kontrole ihtiyaç duyarsanız, dosyayı "java tarzı" bir arayüzle tekrarlayabilirsiniz:

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

4
Bu iyi çalışıyor. Hatta son satırı okur (!). Bir windows tarzı metin dosyası ise \ r tutar bahsetmeye değer. line.trim () ekstra kaldırma hile yapar.
Pierre-Luc Bertrand

Bu girdinin yalnızca isimlendirilmiş bir dosyadan olabileceği, ancak (açık ve son derece önemli bir örnek için process/stdin) alt optimal olmasıdır . En azından, eğer yapabilirse, kodu okumak ve denemek kesinlikle açık değildir.
Sivri

2
Bu arada readlineçekirdek modülü kullanarak bir dosyadan satırları okumak için yerleşik bir yol vardır .
Dan Dascalescu

Bu eski, ama herhangi birinin üzerine tökezlemesi durumunda: function(reader)ve function(line)olmalıdır: function(err,reader)ve function(err,line).
jallmer

1
Sadece kayıt için, line-readerdosyayı eşzamansız olarak okur. Eşzamanlı alternatifline-reader-sync
Prajwal Dhatwalia

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

42
Bu işlem bellekteki tüm dosyayı okur ve ardından satırlara böler. Soruların sorduğu şey bu değil. Mesele, büyük dosyaları talep üzerine sırayla okuyabilmektir.
Dan Dascalescu

2
Bu benim kullanım durumuma uygun, bir komut dosyasından başka bir biçime girdi dönüştürmek için basit bir yol arıyordu. Teşekkürler!
Callat

23

2019'da güncelleme

Resmi Nodejs belgelerinde zaten harika bir örnek yayınlanmıştır. buraya

Bu, makinenize en son Nodejs'in kurulu olmasını gerektirir. > 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();

bu cevap, EOF'u belirgin bir şekilde belirten vaat temelli davranışı sayesinde yukarıdaki her şeyden çok daha iyidir.
phil294

Teşekkürler, bu tatlı.
Goran Stoyanov

3
Belki bu diğerleri için açıktır, ancak hata ayıklamak için biraz zaman aldı: çağrı ile döngünün başlangıcı awaitarasında herhangi bir s varsa , dosyanın başlangıcından gizemli bir şekilde satırları kaybedersiniz. hemen sahnelerin ardında satırlar yaymaya başlar ve örtük olarak oluşturulmuş olan zaman uyumsuz yineleyici , bu satırlar oluşturulana kadar dinlemeye başlayamaz. createInterface()for awaitcreateInterface()const line of rl
andrewdotn

19

Eski konu, ancak bu işe yarıyor:

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

Basit. Harici bir modüle gerek yoktur.


2
readline is not definedVeya alırsanız fs is not defined, ekleyin var readline = require('readline');ve var fs = require('fs');işe yaraması için. Aksi halde tatlı, tatlı kod. Teşekkürler.
bergie3000

12
Bu yanıt, daha önceki bir yanıtın tam bir kopyasıdır , ancak yorum uyarısı uyarıları olmadan, okuma satırı paketi kararsız olarak işaretlenmiştir (Nisan 2015 itibariyle hala kararsızdır) ve 2013'ün ortalarında satır sonu olmayan bir dosyanın son satırlarını okumada sorun vardı . Son satır sorunu, v0.10.35'te kullandığım ilk kez kırpıldı ve sonra gitti. /
argh

Tek yapmanız gereken bir dosya akışından okunuyorsa , çıktıyı belirtmeniz gerekmez .
Dan Dascalescu

18

Her zaman kendi satır okuyucunuzu çevirebilirsiniz. Bu snippet'i henüz kıyaslamadım, ancak gelen parça akışını doğru '' n 'olmadan satırlara ayırıyor

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

Günlük ayrıştırma sırasında veri biriktirmek için gereken hızlı bir günlük ayrıştırma komut dosyası üzerinde çalışırken bu geldi ve perl veya bash yerine js ve düğüm kullanarak bunu denemek güzel olacağını hissettim.

Her neyse, küçük nodejs komut dosyalarının bağımsız olması ve üçüncü taraf modüllere güvenmemesi gerektiğini hissediyorum, bu nedenle bu sorunun tüm cevaplarını okuduktan sonra, her biri satır ayrıştırmasını işlemek için çeşitli modüller kullanıyor, 13 SLOC yerel nodejs çözümü ilgi çekici olabilir.


Bir şey stdineksik olmadıkça, bunun yanı sıra rastgele dosyalarla çalışmak için bunu genişletmek için önemsiz bir yol yok gibi görünüyor .
hippietrail

3
@hippietrail ReadStreamile bir oluşturabilir fs.createReadStream('./myBigFile.csv')ve bunun yerine kullanabilirsinizstdin
nolith

2
Her parça sadece tam satır içerecek şekilde garantili mi? Çok baytlı UTF-8 karakterlerinin yığın sınırlarında bölünmemesi garanti ediliyor mu?
hippietrail

1
@hippietrail Çok baytlı karakterlerin bu uygulama tarafından doğru bir şekilde işlendiğini düşünmüyorum. Bunun için, öncelikle arabellekleri doğru bir şekilde dizelere dönüştürmeli ve iki arabellek arasında bölünen karakterleri takip etmelidir. Bunu düzgün bir şekilde yapmak için yerleşik StringDecoder
Ernelli

Bu arada readlineçekirdek modülü kullanarak bir dosyadan satırları okumak için yerleşik bir yol vardır .
Dan Dascalescu

12

İle taşıyıcı modülü :

var carrier = require('carrier');

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

Güzel. Bu, herhangi bir giriş dosyası için de geçerlidir: var inStream = fs.createReadStream('input.txt', {flags:'r'}); Ancak sözdiziminiz, .on () yönteminin belgelenmiş yönteminden daha temizdir:carrier.carry(inStream).on('line', function(line) { ...
Brent Faust

Taşıyıcı sadece sap gibi görünüyor \r\nve \nsatır sonları. OS X'ten önceki MacOS tarzı test dosyalarıyla ilgilenmeniz gerekiyorsa, bunlar kullanılır \rve taşıyıcı bunu işlemez. Şaşırtıcı bir şekilde, hala vahşi doğada yüzen bu tür dosyalar var. Ayrıca Unicode BOM'u (bayt sırası işareti) açıkça işlemeniz gerekebilir, bu MS Windows etki alanındaki metin dosyalarının başlangıcında kullanılır.
hippietrail

Bu arada readlineçekirdek modülü kullanarak bir dosyadan satırları okumak için yerleşik bir yol vardır .
Dan Dascalescu

9

Düğümlerde boşaltma / duraklatma / devam ettirme yolu nedeniyle bu satırları işlemeye ve bunları başka bir akışa yazmaya çalışırken Lazy'yi kullanarak satır satır okumak için devasa, büyük bir bellek sızıntısıyla sonuçlandım (bkz: http: // elegantcode .com / 2011/04/06 / dere-js-pompalama-veri-akarsu-ile-bebek-adımlarını-alarak-/ / bu adam btw seviyorum). Nedenini tam olarak anlayabilmek için Lazy'ye yeterince yakından bakmadım, ancak Lazy'den çıkmadan bir tahliyeye izin vermek için okuma akışımı duraklatamadım.

Büyük csv dosyalarını xml belgelerine işlemek için kod yazdım, kodu burada görebilirsiniz: https://github.com/j03m/node-csv2xml

Önceki revizyonları Lazy hattıyla çalıştırırsanız sızıntı yapar. En son revizyon hiç sızmıyor ve muhtemelen bir okuyucu / işlemci için temel olarak kullanabilirsiniz. İçinde bazı özel şeyler olmasına rağmen.

Düzenleme: Sanırım ben de bir zorunluluk / duraklatma / devam bir zorunluluk nedeniyle yeterince büyük xml parçaları yazma buldum kadar Lazy ile benim kod iyi çalıştı unutmayın. Küçük parçalar için iyiydi.


Bu arada readlineçekirdek modülü kullanarak bir dosyadan satırları okumak için çok daha basit bir yol var .
Dan Dascalescu

Evet. Şimdi doğru yol bu. Ama bu 2011'den oldu. :)
j03m

8

Düzenle:

Bir dönüşüm akışı kullanın .


Bir BufferedReader ile satırları okuyabilirsiniz.

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
Bu arada readlineçekirdek modülü kullanarak bir dosyadan satırları okumak için çok daha basit bir yol var .
Dan Dascalescu

7

Orijinal cevabımı gönderdiğimden beri, bölünmenin bir dosyada satır okuma için kullanımı kolay bir düğüm modülü olduğunu gördüm ; Hangi isteğe bağlı parametreleri kabul eder.

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

Çok büyük dosyalar üzerinde test yapmadım. Yaparsanız bize bildirin.


6

Bunun için kapsamlı bir çözüm olmaması beni hayal kırıklığına uğrattı, bu yüzden kendi girişimimi bir araya getirdim ( git / npm ). Kopyalanmış yapıştırılmış özellikler listesi:

  • Etkileşimli hat işleme (geri arama tabanlı, tüm dosyayı RAM'e yüklemez)
  • İsteğe bağlı olarak, bir dizideki tüm satırları döndürür (ayrıntılı veya ham mod)
  • Akışı etkileşimli olarak kesin veya işleme / harita gibi işleme gerçekleştirin
  • Herhangi bir yeni satır kuralını algılama (PC / Mac / Linux)
  • Doğru / son hat tedavisi
  • Çok baytlık UTF-8 karakterlerinin doğru kullanımı
  • Satır başına bayt uzaklığı ve bayt uzunluğu bilgilerini alma
  • Satır tabanlı veya bayt tabanlı ofsetler kullanarak rastgele erişim
  • Rasgele erişimi hızlandırmak için satır ofset bilgilerini otomatik olarak eşleyin
  • Sıfır bağımlılıklar
  • Testler

NIH? Sen karar ver :-)


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

Bunu test edeceğim, ama bana söyleyebilir misin, çok baytlı karakterleri asla kırmamak garanti mi? (UTF-8 / UTF-16)
hippietrail

2
@hippietrail: Karakter akışı yerine bayt akışı üzerinde çalışmasına rağmen cevap UTF-8 için hayır. Yeni satırlara (0x0a) son verir. UTF-8'de, çok baytlı bir karakterin tüm baytlarının yüksek dereceli bitleri vardır. Bu nedenle, hiçbir çokbaytlı karakter gömülü bir yeni satır veya başka bir ortak ASCII karakteri içeremez. Ancak UTF-16 ve UTF-32 başka bir konudur.
George

@George: Sanırım birbirimizi yanlış anlıyoruz. CR ve LF'nin her ikisi de ASCII aralığında olduğundan ve UTF-8 128 ASCII karakterini değişmeden koruduğu için, ne CR ne de LF, çok baytlı UTF-8 karakterinin bir parçası olamaz. Ne soruyordu olup olmadığıdır dataçağrısında stream.on("data")gibi kudretini hiç başlaması veya bir multibyte UTF-8 karakter yalnızca bir kısmı ile uç olan U+10D0, üç bayt oluşane1 83 90
hippietrail

1
Bu, "yeni satır" haline gelmeden önce tüm dosya içeriğini belleğe yükler. Bu bir seferde bir satır OKUYMAZ, bunun yerine TÜM satırları alır ve "yeni satır" arabellek uzunluğuna göre ayırır. Bu yöntem, bir akış oluşturma amacını yener.
Justin

Bu arada readlineçekirdek modülü kullanarak bir dosyadan satırları okumak için çok daha basit bir yol var .
Dan Dascalescu

5

Aynı sorunu çözmek istedim, temelde Perl'de ne olurdu:

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

Benim kullanım durumum sunucu değil, sadece bağımsız bir komut dosyasıydı, bu nedenle senkron iyiydi. Bunlar benim kriterlerimdi:

  • Birçok projede yeniden kullanılabilen minimum senkron kod.
  • Dosya boyutunda veya satır sayısında sınır yoktur.
  • Hatların uzunluğu için sınır yoktur.
  • BMP'nin ötesindeki karakterler de dahil olmak üzere UTF-8'de tam Unicode ile başa çıkabilir.
  • * Nix ve Windows satır sonlarını işleyebilir (benim için eski stil Mac gerekmez).
  • Satırlara dahil edilecek satır sonları karakter (ler) i.
  • Satır sonu karakterleri olsun veya olmasın son satırı işleyebilir.
  • Node.js dağıtımında bulunmayan harici kitaplıkları kullanmayın.

Bu, node.js'de düşük düzeyli komut dosyası türü kodu hakkında bir fikir edinmem ve Perl gibi diğer komut dosyası dillerinin yerine ne kadar geçerli olduğuna karar vermem için bir projedir.

Şaşırtıcı bir çaba ve birkaç yanlış başlangıçtan sonra bu geldi kod. Oldukça hızlı ama beklediğimden daha az önemsiz: (GitHub'da çatallayın)

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

Muhtemelen daha fazla temizlenebilir, deneme yanılma sonucuydu.


5

Çoğu durumda bu yeterli olmalıdır:

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

Jeneratör tabanlı hat okuyucu: 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

Bir dosyayı satır satır okumak ve bunu başka bir dosyaya yazmak istiyorsanız:

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

Seninki ile kofrasa'nın cevabı arasındaki fark nedir?
Buffalo

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

Aynı sorunu yaşadım ve yukarıdaki çözüm diğerlerine benziyor görünüyor ama aSync ve büyük dosyaları çok hızlı bir şekilde okuyabilir

Umut etmek bu yardım etmek


1

Bunu iyi yapan ve diğer birkaç proje npm readline tarafından kullanılan küçük bir modüle sahibim Not thay düğüm v10'da yerel bir readline modülü var, bu yüzden modülümü linebyline olarak yeniden yayınladım https://www.npmjs.com/package/ satır satır

modülü kullanmak istemiyorsanız işlev çok basittir:

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

Başka bir çözüm, ardışık yürütücü nsynjs üzerinden mantığı çalıştırmaktır . Düğüm okuma hattı modülünü kullanarak dosyayı satır satır okur ve vaat veya özyineleme kullanmaz, bu nedenle büyük dosyalarda başarısız olmaz. Kod şöyle görünecektir:

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

Yukarıdaki kod bu incelemeye dayanmaktadır: https://github.com/amaksr/nsynjs/blob/master/examples/node-readline/index.js


1

Bu tür işlemleri yaparken kendimize sormamız gereken iki soru:

  1. Bunu gerçekleştirmek için kullanılan bellek miktarı nedir?
  2. Bellek tüketimi dosya boyutuyla birlikte önemli ölçüde artıyor mu?

Gibi çözümler require('fs').readFileSync()tüm dosyayı belleğe yükler. Bu, işlemleri gerçekleştirmek için gereken bellek miktarının neredeyse dosya boyutuna eşit olacağı anlamına gelir. Bundan daha büyük bir şey için bunlardan kaçınmalıyız50mbs

Bu kod satırlarını işlev çağrısından sonra yerleştirerek bir işlev tarafından kullanılan bellek miktarını kolayca izleyebiliriz :

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

Şu anda büyük bir dosyadan belirli satırları okumanın en iyi yolu düğümün readline'ını kullanmaktır . Dokümantasyonun inanılmaz örnekleri var .

Bunu yapmak için üçüncü taraf bir modüle ihtiyacımız olmamasına rağmen. Ancak, bir kurumsal kod yazıyorsanız, birçok uç durumu ele almanız gerekir. Tüm bu kenar durumları işlemek için Apick Dosya Depolama adlı çok hafif bir modül yazmak zorunda kaldım .

Apick Dosya Depolama modülü: https://www.npmjs.com/package/apickfs Belgeler: https://github.com/apickjs/apickFS#readme

Örnek dosya: https://1drv.ms/t/s!AtkMCsWInsSZiGptXYAFjalXOpUx

Örnek: Kurulum modülü

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

Bu yöntem 4 GB'a kadar yoğun dosyalarla başarıyla test edilmiştir.

big.text 163.845 satırlı yoğun bir metin dosyasıdır ve 124 Mb'dir. Bu dosyadan 10 farklı satır okuma komut dosyası, sadece yaklaşık 4.63 MB Bellek kullanır. Ve geçerli JSON'u Nesnelere veya Dizilere ücretsiz olarak ayrıştırır. 🥳 Müthiş !!

Çok az bellek tüketimi ile dosyanın tek bir satırını veya yüzlerce satırını okuyabiliriz.


0

Bunu kullanıyorum:

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

bu işlevi bir akışta kullanın ve yayılacak satır olaylarını dinleyin.

GR-


0

Büyük olasılıkla readlineüst yanıtın önerdiği gibi modülü kullanmanız gerekirken , readlinesatır okuma yerine komut satırı arabirimlerine yönlendirilmiş gibi görünüyor. Ayrıca tamponlama konusunda biraz daha opak. (Akış hattı yönlendirmeli bir okuyucuya ihtiyaç duyan herkes muhtemelen arabellek boyutlarını değiştirmek isteyecektir). Readline modülü ~ 1000 satır iken, istatistikler ve testlerle birlikte 34'tür.

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

İşte 19 satırda istatistikler olmadan daha da kısa bir sürüm:

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

Günlük hat işlemenin tüm mantığını bir npm modülü olarak sararım: line-kit 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

Ben onun bir dizin ve dosya listesine dahil olmadığını kontrol ettikten emin olduktan sonra aşağıdaki satırları okuma satırları kullanı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);

})();

-1

Yukarıdaki tüm cevapları inceledim, hepsi çözmek için üçüncü taraf kütüphanesini kullanıyor. Düğümün API'sinde basit bir çözümü var. Örneğin

const fs= require('fs')

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

stream.on('data', chunk => {
    let row = chunk.toString('ascii')
}))
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.