Jens Irrgang: / Perl - Datei lesen und schreiben tut nicht wie es soll.

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

  1. 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

    --
    Der Optimist: Das Glas  ist halbvoll.  - Der Pessimist: Das Glas ist halbleer. - Der Ingenieur: Das Glas ist doppelt so groß wie nötig.
    1. 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

      1. 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

        1. 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