/ Perl - Datei lesen und schreiben tut nicht wie es soll.
Jens Irrgang
- cgi
Hallo, und guten Morgen.
Ich habe ein kleines Problem mit einem Script, welches nicht so tut wie ich es will. Konkret - ich will eine Zahl auslesen und wieder zurück schreiben, in einem Arbeitsgang - also mit einem geöffneten Dateihandle.
Der Code soweit:
<pre>
sub get_number {
open(NUMBER,"+<$basedir/$datafile");
flock(NUMBER, 2);
$num = <NUMBER>;
if ($num == 999999 || $num !~ /^\d+$/) {
$num = "10000";
}
else {
$num++;
}
print NUMBER $num;
flock(NUMBER, 8);
close(NUMBER);
}
</pre>
Laut dem Perl-Kochbuch von O'Reilly bewirkt das +< ein öffnen zum Lesen und aktualisieren. In meinem Fall wird aber die neue Nummer nagehängt, nicht der alte Wert überschrieben. Ist das jetzt ein Problem oder habe ich da nur was falsch interpretiert?
Aus Gründen der Sicherheit (für das Script und die daraus resultierenden Dateien) sollte das alles in einem Schritt erledigt werden, damit die Nummer nicht von einer anderen Instanz erneut ausgelesen wird und somit es zu Fehlern kommt.
Jens
Hi,
sub get_number {
open(NUMBER,"+<$basedir/$datafile");
flock(NUMBER, 2);
$num = <NUMBER>;
if ($num == 999999 || $num !~ /^\d+$/) {
$num = "10000";
}
else {
$num++;
}
Auf welcher POSITION steht der Filepointer zu diesem Zeitpunkt?
Warum wird also nicht überschrieben, sondern angehängt?
Was mußt Du also mit dem Filepointer machen?
Kleiner Hinweis: perldoc -f seek
print NUMBER $num;
flock(NUMBER, 8);
close(NUMBER);
}
cu,
Andreas
Hey Andreas,
das war das wonach ich gesucht habe. Spitze.
Hier nun das korrigierte funktionierende Sub.
sub get_number {
open(NUMBER,"+<$basedir/$datafile");
flock(NUMBER, 2);
$num = <NUMBER>;
if ($num == 999999 || $num !~ /^\d+$/) {
$num = "10000";
}
else {
$num++;
}
seek(NUMBER, 0, 0);
print NUMBER $num;
close(NUMBER);
}
Danke
Jens
Hallo Jens,
sub get_number {
open(NUMBER,"+<$basedir/$datafile");
flock(NUMBER, 2);
$num = <NUMBER>;
if ($num == 999999 || $num !~ /^\d+$/) {
$num = "10000";
}
else {
$num++;
}
seek(NUMBER, 0, 0);
print NUMBER $num;
close(NUMBER);
}
besser:
use POSIX qw'SEEK_SET';
use Fcntl qw':flock';
sub get_number {
local *NUMBER;
open NUMBER,'+<'.$basedir.'/'.$datafile or die $!;
flock NUMBER,LOCK_EX or die $!;
$num = <NUMBER>;
if(!defined $num || $num !~ /^\d+$/ || $num == 999999) {
$num = 10000;
}
else {
$num++;
}
seek NUMBER,0,SEEK_SET or die $!;
print NUMBER $num;
close NUMBER;
}
Also benutzen symbolischer Konstanten (die Werte koennen
System-abhaengig sein) und das Abfangen von Fehlern (seek,
open, etc koennen alle fehlschlagen) und das umstellen der
Bedingung in if (ein numerischer Vergleich mit undef oder
einem String gibt eine Warning (zurecht)).
Gruesse,
CK
Hallo Christian,
dieser Schnipsel ist aus einem fertigen Script, welches ich heruntergeladen habe. Ich habe es nur etwas für meine Bedürfnisse angepasst. Im Moment schreibe ich ein eigenes Script, und in diesem werden die Fehler dann auch abgefangen und registriert.
Aber das hier war jetzt eine Hauruck-Aktion, weil die bisherige Funktion unter ungünstigen Umständen Fehler verursachte.
Danke
Jens