javascript - Hur kan jag läsa en fil rad för rad från botten med NodeJS?


Jag har en lång loggfil som jag behöver läsa från botten, rad för rad, och stoppa när ett visst villkor är uppfyllt, och sedan returnera den raden. Detta behöver också fungera på Windows. Filen kommer antagligen att vara ganska lång, så jag vill inte läsa hela filen och sedan vända på den.

Jag använder för närvarande reverse-line-reader, men det har inte uppdaterats sedan 2015 och den asynkrona funktionaliteten lämnar mycket att önska.

Varje annat paket jag har sett är antingen arkiverat, kräver att jag vet antalet rader jag vill ha i förväg, eller bearbetar inte rad för rad.

Finns det något sätt att göra detta i vanlig Node, eller finns det ett paket som jag inte har sett som gör det jag behöver?

Nuvarande kod, om det alls är till hjälp för att förklara vad jag behöver:

reverseLineReader.eachLine(this.#path, (raw: string, last: boolean) => {
    if (raw) { // skip blank line at end of file
        const line = JSON.parse(raw)

        if (line.event === 'FSDJump') {
            this.location = new System(line)
            Log.write(`Current location set to ${this.location.name}.`)
            this.emit('ENTERED_NEW_SYSTEM')
            return false // stop reading

        } else if (last) {
            log('Unable to find last hyperspace jump. Searching for last known location.')
            return false
        }
    }
})

Tack!

Svar #1

Här är en grundläggande vanilla Node-implementation av en readBackwards-metod som läser ett antal byte från slutet av en fil.

För enkelhets skull öppnar det filen, använder stat för att få filstorleken och använder sedan read med ett offset beräknat från slutet av filen.

Om du behöver läsa mer från slutet av filen bör du anropa stat utanför metoden och skicka in storleken som ett argument för att inte anropa stat onödigt ofta. Då kan du i princip öka positionFromEnd i varje iteration med storleken på din buffert för att få den att glida över filen från slutet till början.

const fs = require("fs");
const { Buffer } = require("buffer");

function readBackwards(
  file,
  buffer,
  offsetInBuffer,
  length,
  positionFromEnd,
  callback
) {
  fs.open(file, "r", 0666, (err, fd) => {
    if (err) return callback(err);

    fs.fstat(fd, (err, stat) => {
      if (err) return callback(err);

      fs.read(
        fd,
        buffer,
        offsetInBuffer,
        length,
        Math.max(stat.size - length - positionFromEnd, 0),
        (err, bytesRead, buffer) => {
          if (err) return callback(err);

          fs.close(fd, (err) => {
            return callback(err, bytesRead, buffer);
          });
        }
      );
    });
  });
}

Prova det här: https://codesandbox.io/p/sandbox/loving-mestorf-hgro1p?file=%2Findex.js%3A8%2C13

Redigera: För att läsa rad för rad skulle du sammanfoga det du har läst under iterationerna tills den första radbrytningen inträffar. Sedan delar du vid radbrytningen(a) och kan bearbeta de kompletta raderna innan du läser mer från filen.