Zeilen löschen ----
alligator
- perl
0 alligator0 Klaus Mock0 alligator0 Klaus Mock
Hi zusammen,
ich hab folgendes Problem.
Ich überprüfe X-Text-Dateien auf ihre MB - Größe
und wenn sie eine bestimmte Größe überschreiten, dann lösche ich die Datei bis auf die letzten X Zeilen.
Bis jetzt hab ich:
1 #!/usr/bin/perl -w2 use strict;3 4 my $dir = "."; 5 my $zeile = 10;6 my @array;7 8 opendir(DIR,"$dir")|| die "Kann Pfad nicht oeffnen $!";9 @array = readdir (DIR);10 closedir(DIR);11 #@array = glob("*.txt");12 13 14 foreach (@array)15 {16 17 if (($_ =~ /.txt$/)&& (300000 < (-<span class="operator">s "$_")))18 {19 my @dummy;20 open (DATEI, "$_") || die "Kann Datei nicht oeffnen $!";21 @dummy = ;22 close (DATEI);23 my $l = @dummy;24 print "Länge ist : ".(-s "$_")."\n"; 25 if ($l > $zeile)26 {27 my @dummy2;28 print " Zeilen:$l - Datei:$_ \n";29 my $mx =$l-1;30 my $myz = $l-$zeile;31 for ($myz;$mx>=$myz;$myz++)32 { 33 push(@dummy2, $dummy[$myz]);34 }35 open (DATEI, ">$_") || die "Kann Datei nicht oeffnen $!";36 print DATEI @dummy2;37 close (DATEI);38 }39 }40 }
Es tut zwar, aber irgendwie glaub ich, das es ziemlicher Muell ist und auch viel einfacher und sauberer geht.
Das Script läuft auf Solaris, d.h. zur Not könnt ich auch Unix-Befehle einbauen. Den Befehl dafür hab ich auch
tail -ZEILE DATEI > DATEI un der klappt auch aber nicht im Perl-Scriipt.
Versucht hab ich
system ("tail -$zeile $_ > $_");
aber irgendwie will mein Perl das nicht und gibt ne Fehlermeldung aus (die ich grad nicht mehr weiss).
Vielleicht kann mir jemand sowohl mit dem Unix-Befehl als auch plattformunabhängig, also nur mit Perl weiterhelfen.
thx
alligator
Sorry hier nochmal der QT, den hats mir zerhauen ...
#!/usr/bin/perl -w
use strict;
my $dir = ".";
my $zeile = 10;
my @array;
opendir(DIR,"$dir")|| die "Kann Pfad nicht oeffnen $!";
@array = readdir (DIR);
closedir(DIR);
#@array = glob("*.txt");
foreach (@array)
{
if (($_ =~ /.txt$/)&& (300000 < (-s "$_")))
{
my @dummy;
open (DATEI, "$_") || die "Kann Datei nicht oeffnen $!";
@dummy = <DATEI>;
close (DATEI);
my $l = @dummy;
print "Länge ist : ".(-s "$_")."\n";
if ($l > $zeile)
{
my @dummy2;
print " Zeilen:$l - Datei:$_ \n";
my $mx =$l-1;
my $myz = $l-$zeile;
for ($myz;$mx>=$myz;$myz++)
{
push(@dummy2, $dummy[$myz]);
}
open (DATEI, ">$_") || die "Kann Datei nicht oeffnen $!";
print DATEI @dummy2;
close (DATEI);
}
}
}
Hallo,
my $filename;
foreach $filename (@array)
{
if (($_ =~ /.txt$/)&& (300000 < (-s "$_")))
wenn dann
(-s "$dir/$_")
Da $_ nur den Dateinamen, ohne Pfad beinhaltet.
Aber nun
if (($filename =~ /.txt$/)&& (300000 < (-s "$dir/$filename")))
{
my @dummy;
open (DATEI, "$_") || die "Kann Datei nicht oeffnen $!";
Auch hier
open (DATEI, "$dir/$filename") || die "Kann Datei nicht oeffnen $!";
Den Rest spare ich mir, und schreibe:
seek(DATEI,-300000,2); # springe vom Dateiende 300000 Bytes vor
<DATEI>; # die halbe Zeile vergessen wir, wenn DU willst
@dummy = <DATEI>;
close (DATEI);
open (DATEI, ">$dir/$filename") || die "Kann Datei nicht schreiben $!";
print DATEI @dummy;
close(DATEI);
}
}
Ich würde zwar noch mit zwei Dateihandles (IN,OUT) arbeiten, dadurch könnte ich mir @dummy sparen, aber das ist schon ein bißchen Geschmacksfrage.
Grüße
Klaus
open (DATEI, "$dir/$filename") || die "Kann Datei nicht oeffnen $!";
Den Rest spare ich mir, und schreibe:
seek(DATEI,-300000,2); # springe vom Dateiende 300000 Bytes vor
<DATEI>; # die halbe Zeile vergessen wir, wenn DU willst
@dummy = <DATEI>;
close (DATEI);
HI erstmal thx für die Antwort.
Wenn ich das jetzt richtig verstehe , dann passiert das alle Bytes die nach den 300000 kommen wieder in die neue Zeile geschrieben wird. Aber das will ich ja nicht wirklich, sondern ich will, dass die letzten 20 Zeilen in die Datei wieder geschreiben wird. Kann man das nicht auch irgendwie machen ?
cu
alligator
Hallo,
HI erstmal thx für die Antwort.
Wenn ich das jetzt richtig verstehe , dann passiert das alle Bytes die nach den 300000 kommen wieder in die neue Zeile geschrieben wird.
Nein, es würde dafür sorfen, daß danach nicht mehr als 300000 Bytes in der Datei sind, allerdinsg nur vollständige Zeilen. Im schlechtesten Falle würde eine komplette Zeile umsonst 'weggeschmissen'.
Aber das ist ja quasi Schnee von gestern, denn..
... das will ich ja nicht wirklich, sondern ich will, dass die letzten 20 Zeilen in die Datei wieder geschreiben wird. Kann man das nicht auch irgendwie machen ?
Spontan würde mir da einfallen, daß Du den Inhalt der Datei in das Array einliest, und nur die letzten 20 Elemente des Arrays wieder rausschreibst. Dabei kann dir ein bißchen grundlegende Rechenoperationen, wie eine Subtraktion, und das ermitteln der Anzahl der Elemente des Arrays sicherlich wertvolle Hilfe leisten.
Lies bitte dazu die Dokumentation zur Funktion, oder eigentlich Operator, 'scalar' (perldoc -f scalar).
Der Rest sollte dann ein Konderspiel sein.
Grüße
Klaus
Spontan würde mir da einfallen, daß Du den Inhalt der Datei in das Array einliest, und nur die letzten 20 Elemente des Arrays wieder rausschreibst. Dabei kann dir ein bißchen grundlegende Rechenoperationen, wie eine Subtraktion, und das ermitteln der Anzahl der Elemente des Arrays sicherlich wertvolle Hilfe leisten.
Lies bitte dazu die Dokumentation zur Funktion, oder eigentlich Operator, 'scalar' (perldoc -f scalar).
Hi,
ähh bis jetzt hab ich das genauso (siehe Posting 1+2) und hab gefragt ob man das besser machen könnte, da ich ja eine ca 500000 Zeile-Datei erst einlese und dann nur die letzten 20 Zeilen brauche .... ---> unnötige Systemlast.
Aber anscheinen geht das nicht anderst ....
cu
alligator
Hallo,
ähh bis jetzt hab ich das genauso (siehe Posting 1+2) und hab gefragt ob man das besser machen könnte, da ich ja eine ca 500000 Zeile-Datei erst einlese und dann nur die letzten 20 Zeilen brauche .... ---> unnötige Systemlast.
Aber anscheinen geht das nicht anderst ....
Wenn Du natürlich irgendwie abschätzen kannst, wie lange eine Zeile sein kann, dann könntest Du auch die ungefähr die Größe von 20 Zeilen berechnen. Diesen Wert kannst Du dann für ein seek() verwenden, um den Großteil der Datei zu überspringen, womit sich die Menge der einzulesenden Daten wahrscheinlich erheblich reduziert.
Allerdinsg würde ich mir bei 500.000 Zeilen schon Gedanken machen, ob es nicht besser wäre, das ganze in einer Datenbank zu verwalten. Dmait könntest Du diese Aufräumarbeiten wesentlcih eleganter und auch performanter gestalten.
Grüße
Klaus