Marko: Directory lesen mit Perl

Hallo Leute,

und mal wieder richte ich eine kleine, dumme Frage an das Forum, aber dazu isses ja da.
Also das Problem:

Ein Perlscript soll bei jedem Aufruf eine Datei im Verzeichniss anlegen, diese Dateien sollen als Namen eindeutige, durchgehende Nummern haben (z.B. 00001.dat ; 00002.dat...), was für Funktionen gibt es in Perl um festzustellen, welche Dateinamen schon existieren, und wie verhindere ich Kollisionen, wenn sich zwei Aufrufe überschneiden (sehr unwahrscheinlich aber nicht unmöglich).
Die Möglichkeit eine zusätzliche Log-Datei mit einer Zählvariable einzurichten, fällt mir zwar spontan auch ein, aber das muss doch eleganter gehen.

Vielen Dank

Marko

  1. Hallo Leute,

    und mal wieder richte ich eine kleine, dumme Frage an das Forum, aber dazu isses ja da.
    Also das Problem:

    Ein Perlscript soll bei jedem Aufruf eine Datei im Verzeichniss anlegen, diese Dateien sollen als Namen eindeutige, durchgehende Nummern haben (z.B. 00001.dat ; 00002.dat...), was für Funktionen gibt es in Perl um festzustellen, welche Dateinamen schon existieren, und wie verhindere ich Kollisionen, wenn sich zwei Aufrufe überschneiden (sehr unwahrscheinlich aber nicht unmöglich).
    Die Möglichkeit eine zusätzliche Log-Datei mit einer Zählvariable einzurichten, fällt mir zwar spontan auch ein, aber das muss doch eleganter gehen.

    Also, wenn du sehen willst, ob ne Datei da ist, dann geht das glaube ich mit if (-e "/home/ich/datei") { Datei ist da }. Mit dem anderen Problem hab ich mich auch schon auseinander gesetzt. Mann könnte vielleicht FastCGI verwenden. Das wurde eigendlich nicht für solche Sachen gemacht, sollte aber trotzdem gehen. Dann gibt es da noch flock. Damit kannst du ne Datei gegen lesen und, ich glaube auch schreiben sichern.

  2. Hi,

    Ein Perlscript soll bei jedem Aufruf eine Datei im Verzeichniss anlegen, diese Dateien sollen als Namen eindeutige, durchgehende Nummern haben (z.B. 00001.dat ; 00002.dat...), was für Funktionen gibt es in Perl um festzustellen, welche Dateinamen schon existieren, und wie verhindere ich Kollisionen, wenn sich zwei Aufrufe überschneiden (sehr unwahrscheinlich aber nicht unmöglich).
    Die Möglichkeit eine zusätzliche Log-Datei mit einer Zählvariable einzurichten, fällt mir zwar spontan auch ein, aber das muss doch eleganter gehen.

    ich finde die Zählerdatei schon recht elegant, zumindest wenn Du im Verzeichnis 15.000 Dateien hast. Ansonsten gibt es (neben -e, siehe Erik) die Befehle opendir und readdir zu diesem Zweck.

    Um Überschneidungen zu vermeiden sollte das Script "öffentlich mitteilen", daß es gerade eine neue Datei erstellt, andere Instanzen sollten bei dieser Mitteilung einfach warten. Ich mache das immer, indem ich eine Dummy-Datei erstelle, die ich vorher auf Existenz prüfe. Ist sie da, warte ich mit sleep eine Sekunde. Ist sie auch nach 5 Sekunden noch da, war's offenbar eine Fehlmitteilung und ich schreibe die Datei trotzdem.

    Cheatah

    1. Hi Cheatah!

      Um Überschneidungen zu vermeiden sollte das Script "öffentlich mitteilen", daß es gerade eine neue Datei erstellt, andere Instanzen sollten bei dieser Mitteilung einfach warten. Ich mache das immer, indem ich eine Dummy-Datei erstelle, die ich vorher auf Existenz prüfe. Ist sie da, warte ich mit sleep eine Sekunde. Ist sie auch nach 5 Sekunden noch da, war's offenbar eine Fehlmitteilung und ich schreibe die Datei trotzdem.

      Das mit der Dummy-Datei kann aber auch schon mal in die Hose gehen. Angenommen zwei Prozesse
      machen sich gleichzeitig daran diese Datei zu erzeugen. Beide werde sie nicht "sehen" und gehen
      dann davon aus, daß sie jetzt zuschlagen können. Also wird diese Datei zweimal angelegt, was
      ja nicht unbedingt in die Hose gehen muß. Jedoch gehen jetzt bei Prozesse davon aus, daß sie
      ganz nach Gusto im Verzeichnis Dateien anlegen dürfen ....

      Meine Idee hierzu wäre, zuerst eine Datei mit der Prozess-ID anzulegen. Diese sollte eigentlich
      eindeutig sein, solange man nicht mit Sub-Prozessen rumspielt. Anschließend versucht man dann, die Datei in die eigentliche Zieldatei umzubenennen - was nur gehen sollte, wenn diese
      noch nicht existiert. Bei dieser Variante kann ich natürlich auch gleich die Log-Datei 0042.log
      erzeugen. Bei einem Fehler probiere ich die nächste Nummer. Um nicht unbedingt von vorne
      anfangen zu müssen, kann ich noch vorher in die directory schauen, und den höchsten Wert
      als Startwert nutzen.

      ciao,
         Jörk

      1. Hi Jörk,

        Meine Idee hierzu wäre, zuerst eine Datei mit der Prozess-ID anzulegen.

        die Idee ist ziemlich gut. Das Problem hatte ich schon gesehen, nur bisher als derartig unwahrscheinlich angesehen, daß ich es in Kauf genommen habe. Jetzt fehlt mir noch die Variable/der Befehl, womit ich die Prozess-ID herausfinden kann :-)

        Was hälst Du von folgender Vorgehensweise:

        LABEL:
        my $flockcount=0;
        while (-e $flockdatei && $flockcount < 5) { $flockcount++; sleep(1); }
        open(FLOCK,">$flockdatei");
        print FLOCK $prozess-id;
        close(FLOCK);

        Hier könnte sicherheitshalber noch eine kurze Pause eingelegt werden, vor allem folgt jetzt der Test:

        open(FLOCK,$flockdatei);
        my $pid=<FLOCK>;
        close(FLOCK);
        if ($pid != $prozess-id) { goto LABEL; }

        Schreibzugriff gewährt :-)

        Ich bin jetzt nicht ganz sicher, ob die goto-Geschichte so ganz korrekt ist. Abgesehen davon (und davon, daß ich ein paar Variablen voraussetze), würde dies Deiner Meinung nach sicher sein?

        Cheatah

        1. Hi!

          Was hälst Du von folgender Vorgehensweise:

          LABEL:
          my $flockcount=0;
          while (-e $flockdatei && $flockcount < 5) { $flockcount++; sleep(1); }
          open(FLOCK,">$flockdatei");
          print FLOCK $prozess-id;
          close(FLOCK);

          Hier könnte sicherheitshalber noch eine kurze Pause eingelegt werden, vor allem folgt jetzt der Test:

          open(FLOCK,$flockdatei);
          my $pid=<FLOCK>;
          close(FLOCK);
          if ($pid != $prozess-id) { goto LABEL; }

          Schreibzugriff gewährt :-)

          Ich bin jetzt nicht ganz sicher, ob die goto-Geschichte so ganz korrekt ist. Abgesehen davon (und davon, daß ich ein paar Variablen voraussetze), würde dies Deiner Meinung nach sicher sein?

          Eigentlich wollte ich mit der Prozess-ID Sache den Aufwand DRASTISCH reduzieren. Deine Lösung nutzt aber zumindest immer noch flock ...

          Ich dachte eher an so etwas wie:

          open(NUMMER, "$$.dummy");
          print NUMMER, 'blablabla';
          close NUMMER;

          $zahl = 42;
          until (rename("$$.dummy", "$zahl.log")) {$zahl ++}

          Bin mir grad' aber nicht sicher, ob rename wirklich so reagiert, wie wir das brauchen ...

          ciao,
             Jörk

          1. Hi,

            LABEL:
            my $flockcount=0;
            while (-e $flockdatei && $flockcount < 5) { $flockcount++; sleep(1); }
            open(FLOCK,">$flockdatei");
            print FLOCK $prozess-id;
            close(FLOCK);

            Hier könnte sicherheitshalber noch eine kurze Pause eingelegt werden, vor allem folgt jetzt der Test:

            open(FLOCK,$flockdatei);
            my $pid=<FLOCK>;
            close(FLOCK);
            if ($pid != $prozess-id) { goto LABEL; }

            Schreibzugriff gewährt :-)

            Eigentlich wollte ich mit der Prozess-ID Sache den Aufwand DRASTISCH reduzieren. Deine Lösung nutzt aber zumindest immer noch flock ...

            nein, nur das FileHandle heißt so. Ein flock() ist aber nicht mehr dabei.

            Ich dachte eher an so etwas wie:

            open(NUMMER, "$$.dummy");
            print NUMMER, 'blablabla';
            close NUMMER;

            $zahl = 42;
            until (rename("$$.dummy", "$zahl.log")) {$zahl ++}

            Bin mir grad' aber nicht sicher, ob rename wirklich so reagiert, wie wir das brauchen ...

            Halte ich nicht für besonders sinnvoll. Zunächst einmal würde ich das OS nicht mit dauernden Fehlermeldungen belasten... also mit while(-e) arbeiten ;-) Vor allem aber funktioniert dies ausschließlich bei einem System, das fortlaufend Dateien der Form "xyz.log" erstellt, also nur bei z.B. Foren oder Guestbooks. Das Flock-Problem gibt es aber auch bei Scripts, die nur auf eine einzige Datei zugreifen - und sei es nur ein Counter!

            Jedenfalls habe ich jetzt gelernt, daß die Prozess-ID in $$ gespeichert ist, und daß ich doch öfter mal perldoc perlvar durchlesen sollte ;-) Da gibt es doch mehr Variablen, als ich ursprünglich dachte...

            Cheatah

            1. Hi nochmal!

              Eigentlich wollte ich mit der Prozess-ID Sache den Aufwand DRASTISCH reduzieren. Deine Lösung nutzt aber zumindest immer noch flock ...

              nein, nur das FileHandle heißt so. Ein flock() ist aber nicht mehr dabei.

              <<bäng, reingefallen>> Da hab ich wohl mal wieder nicht genau hingeschaut ;-)

              Ich dachte eher an so etwas wie:

              open(NUMMER, "$$.dummy");
              print NUMMER, 'blablabla';
              close NUMMER;

              $zahl = 42;
              until (rename("$$.dummy", "$zahl.log")) {$zahl ++}

              Bin mir grad' aber nicht sicher, ob rename wirklich so reagiert, wie wir das brauchen ...

              Halte ich nicht für besonders sinnvoll. Zunächst einmal würde ich das OS nicht mit dauernden Fehlermeldungen belasten... also mit while(-e) arbeiten ;-) Vor allem aber funktioniert dies ausschließlich bei einem System, das fortlaufend Dateien der Form "xyz.log" erstellt, also nur bei z.B. Foren oder Guestbooks. Das Flock-Problem gibt es aber auch bei Scripts, die nur auf eine einzige Datei zugreifen - und sei es nur ein Counter!

              Nun ist es aber an Dir, grad nicht aufgepasst zu haben. Ich ging jedenfalls davon aus, daß die Startfrage in diesem thread sich darum drehte, solche fortlaufenden Dateien zu erzeugen. Die Fehlermeldungen wären ja auch sehr minimal, da der Startwert (42) ja mit Hilfe eines Blickes in die Directory entsprechend gesetzt werden kann ... ist also nur eine spezial-Lösung!

              ciao,
                 Jörk

              Jedenfalls habe ich jetzt gelernt, daß die Prozess-ID in $$ gespeichert ist, und daß ich doch öfter mal perldoc perlvar durchlesen sollte ;-) Da gibt es doch mehr Variablen, als ich ursprünglich dachte...

              Cheatah