10 Stimmen

Wie kann ich in Perl Zeilen vom Ende einer Datei lesen?

Ich arbeite an einem Perl-Skript, um eine CSV-Datei zu lesen und einige Berechnungen durchzuführen. CSV-Datei hat nur zwei Spalten, etwa wie unten.

One Two
1.00 44.000
3.00 55.000

Diese CSV-Datei ist sehr groß, sie kann zwischen 10 MB und 2 GB groß sein.

Derzeit nehme ich eine CSV-Datei mit einer Größe von 700 MB. Ich habe versucht, diese Datei in Notepad und Excel zu öffnen, aber es sieht so aus, als würde keine Software sie öffnen.

Ich möchte vielleicht die letzten 1000 Zeilen aus der CSV-Datei lesen und die Werte sehen. Wie kann ich das tun? Ich kann die Datei nicht in Notepad oder einem anderen Programm öffnen.

Wenn ich ein Perl-Skript schreibe, muss ich die gesamte Datei verarbeiten, bis zum Ende der Datei gehen und dann die letzten 1000 Zeilen lesen.

Gibt es einen besseren Weg dorthin? Ich bin neu in Perl und bin für jeden Vorschlag dankbar.

Ich habe das Netz durchsucht und es gibt einige Skripte wie File::Tail aber ich weiß nicht, ob sie unter Windows funktionieren?

29voto

Michael Carman Punkte 30300

En Datei::ReadBackwards Modul können Sie eine Datei in umgekehrter Reihenfolge lesen. Das macht es einfach, die letzten N Zeilen zu erhalten, solange man nicht von der Reihenfolge abhängig ist. Wenn dies der Fall ist und die benötigten Daten klein genug sind (was in Ihrem Fall der Fall sein sollte), können Sie die letzten 1000 Zeilen in ein Array lesen und dann reverse eso.

11voto

S.Lott Punkte 371691

Unter *nix können Sie den Befehl tail verwenden.

tail -1000 yourfile | perl ...

Dadurch werden nur die letzten 1000 Zeilen in das Perl-Programm geschrieben.

Unter Windows gibt es gnuwin32 y unxutils Pakete haben beide tail Nutzen.

9voto

brian d foy Punkte 124323

Dies hat zwar nur am Rande mit Ihrer Hauptfrage zu tun, aber wenn Sie prüfen wollen, ob ein Modul wie Datei::Tail auf Ihrer Plattform funktioniert, überprüfen Sie die Ergebnisse von CPAN-Prüfer . Die Links am oberen Rand der Modulseite in CPAN-Suche führen Sie zu

file-tail-header
(Quelle: <a href="https://farm4.static.flickr.com/3192/3044332885_53b7f294f4.jpg" rel="nofollow noreferrer">flickr.com </a>)

Ein Blick auf die Matrix zeigt, dass dieses Modul tatsächlich unter Windows und allen getesteten Perl-Versionen ein Problem hat:

file-tail-matrix
(Quelle: <a href="https://farm4.static.flickr.com/3271/3044332679_b46363d973_o.png" rel="nofollow noreferrer">flickr.com </a>)

6voto

Joshua Swink Punkte 3230

Ohne Schwanz ist eine reine Perl-Lösung gar nicht so unvernünftig.

Eine Möglichkeit besteht darin, vom Ende der Datei aus zu suchen und dann Zeilen aus der Datei zu lesen. Wenn Sie nicht genügend Zeilen haben, suchen Sie noch weiter vom Ende entfernt und versuchen es erneut.

sub last_x_lines {
    my ($filename, $lineswanted) = @_;
    my ($line, $filesize, $seekpos, $numread, @lines);

    open F, $filename or die "Can't read $filename: $!\n";

    $filesize = -s $filename;
    $seekpos = 50 * $lineswanted;
    $numread = 0;

    while ($numread < $lineswanted) {
        @lines = ();
        $numread = 0;
        seek(F, $filesize - $seekpos, 0);
        <F> if $seekpos < $filesize; # Discard probably fragmentary line
        while (defined($line = <F>)) {
            push @lines, $line;
            shift @lines if ++$numread > $lineswanted;
        }
        if ($numread < $lineswanted) {
            # We didn't get enough lines. Double the amount of space to read from next time.
            if ($seekpos >= $filesize) {
                die "There aren't even $lineswanted lines in $filename - I got $numread\n";
            }
            $seekpos *= 2;
            $seekpos = $filesize if $seekpos >= $filesize;
        }
    }
    close F;
    return @lines;
}

P.S. Ein besserer Titel wäre etwas wie "Lesen von Zeilen am Ende einer großen Datei in Perl".

6voto

webdevbyjoss Punkte 505

Ich habe eine schnelle Rückwärts-Dateisuche mit folgendem Code auf reinem Perl geschrieben:

#!/usr/bin/perl 
use warnings;
use strict;
my ($file, $num_of_lines) = @ARGV;

my $count = 0;
my $filesize = -s $file; # filesize used to control reaching the start of file while reading it backward
my $offset = -2; # skip two last characters: \n and ^Z in the end of file

open F, $file or die "Can't read $file: $!\n";

while (abs($offset) < $filesize) {
    my $line = "";
    # we need to check the start of the file for seek in mode "2" 
    # as it continues to output data in revers order even when out of file range reached
    while (abs($offset) < $filesize) {
        seek F, $offset, 2;     # because of negative $offset & "2" - it will seek backward
        $offset -= 1;           # move back the counter
        my $char = getc F;
        last if $char eq "\n"; # catch the whole line if reached
        $line = $char . $line; # otherwise we have next character for current line
    }

    # got the next line!
    print $line, "\n";

    # exit the loop if we are done
    $count++;
    last if $count > $num_of_lines;
}

und führen Sie dieses Skript wie folgt aus:

$ get-x-lines-from-end.pl ./myhugefile.log 200

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X