Wie können wir lesen, analysieren und dann „un-lesen“ und den Beginn eines Eingangsstroms in Perl wieder gelesen?

StackOverflow https://stackoverflow.com/questions/4059800

  •  27-09-2019
  •  | 
  •  

Frage

Ich lese und die Verarbeitung eines Stroms von Eingangs von die ARGV Dateihandle in Perl (das heißt das while(<>) Konstrukt) eine reguläre Dateikennung, die STDIN sein kann. Ich brauche aber einen wesentlichen Teil des Eingangs, um zu analysieren, welche von vier verschiedenen, aber sehr ähnlichen Formaten zu erkennen, es in (verschiedenen ASCII-Codierungen von fastq Qualitätsfaktor kodiert wird, siehe hier ). Einmal habe ich, welches Format die Daten in entschieden, muss ich zurück gehen und diese Zeilen ein zweites Mal analysieren, um tatsächlich die Daten zu lesen.

Also brauche ich die ersten 500 Zeilen oder so des Stroms zweimal zu lesen. Oder um es anders aussehen, ich brauche die ersten 500 Zeilen zu lesen, und dann „setzt sie wieder“, damit ich sie wieder lesen kann. Da ich aus STDIN liest kann, kann ich nicht nur an den Anfang suchen zurück. Und die Dateien sind sehr groß, so dass ich nicht nur alles in den Speicher lesen kann (obwohl diese ersten 500 Zeilen in den Speicher einzulesen ok ist). Was ist der beste Weg, dies zu tun?

Alternativ kann ich den Eingangsstrom duplizieren irgendwie?

Edit: Warten Sie eine Minute. Ich habe gemerkt, dass ich nicht die Eingabe als ein großer Strom verarbeiten kann mehr, weil ich unabhängig voneinander bei jedem Datei-Format erkennen müssen. So kann ich nicht ARGV verwenden. Der Rest der Frage steht noch, aber.

War es hilfreich?

Lösung

Wie Sie sagten, wenn das Dateihandle STDIN sein könnte, können Sie nicht seek verwenden, um zurückzuspulen. Aber es ist immer noch recht einfach. Ich würde nicht mit einem Modul stören:

my @lines;

while (<$file>) {
  push @lines, $_;
  last if @lines == 500;
}

... # examine @lines to determine format

while (defined( $_ = @lines ? shift @lines : <$file> )) {
  ... # process line
}

Beachten Sie, dass Sie eine explizite defined in diesem Fall müssen, weil der Sonderfall, dass eine implizite defined einiger while Schleifen fügt nicht auf diesen komplexeren Ausdruck anwenden.

Andere Tipps

Es is ein CPAN-Modul , dass liefert eine unread Methode zur IO::Handle Klasse. Allerdings machen seine Warnungen ein etwas vorsichtig. Ich würde beurteilen ihre Eignung sorgfältig.

Wenn Sie wirklich nur entfernt 500 Zeilen müssen sparen, kurz jeweils angemessen, könnte das Modul genügen; ihr Beispiel macht Gebrauch STDIN.

Aber ich bin nervös über Magie ARGV. Wenn Ihr <> Betreiber mehr verschiedene Dateien verursacht zu öffnen und lesen, dann weiß ich nicht, dass Sie als die zu einer anderen Datei sichern zu können, gehen zur Zeit offen.

Sie könnten also nur die Push-Back-Logik selbst zu schreiben landen. Entweder das, oder eine Art Beschränkung auf ARGV Auferlegung Verarbeitung in Bezug auf mehr Input-Dateien und / oder die Art der STDIN.

Die meisten meiner Programme mit Magie ARGV Verarbeitung haben Wache an ihrem Anfang an, dass Lese so etwas wie:

if (@ARGV == 0 && -t STDIN) {
    # select one or the other of the next two lines:

    # opt 1: emit warning 
    warn "$0: reading stdin from /dev/tty\n";

    # opt 2: populate @ARGV
    @ARGV = grep { -f && -T } <*>;  # glob plain textfiles

 }

Im zweiten Fall oben, wo sie standardmäßig auf dem ganze Ebene Text-Dateien im aktuellen Verzeichnis, sollte man sich auch entscheiden, was zu tun ist, wenn grep die leere Liste erzeugt.

Für einige Programme, die oder zumindest erwarten zugeben Verzeichnis Argumente, ich werde gelegentlich ein leere @ARGV initialisieren stattdessen ".", so dass das Programm standardmäßig den aktuellen Arbeitsverzeichnis des Prozesses.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top