Arno: Textdatei schreiben haut nicht hin!

Hallo!

Ich möchte gerne für meine Seite eine kleine Statistik machen, also wo die Leute herkommen, wieviele Besucher usw. Das ganze soll für ca. 200 CGI generierte Seiten erfolgen.

Naja ist ja kein Problem, dachte ich. Mein CGI schreibt also bei jedem Aufruf einer Seite die gewünschten Daten in ein TXT File.

Ich lese das txt file erst mal ein. verändere ein bisserl was und schreibe es dann wieder raus (zeilenweise)

Das Problem ist jetzt, dass irgendwie das File verhundst wird auch wenn alles zu gehen scheint. Gestern hatte ich 260 Zeilen (Da 260 Besucher), heute hatte ich dann nur mehr 130! Der rest war verschwunden. Da haut also was mit aulesen, verändern und wieder schreiben nicht hin.

Meine Testläufe haben keine Fehler ergeben (ich hab halt keine gefunden). Naja wenn ich ganz oft auf reload (schnell hintereinander) drücke wird die erste Zeile verunstaltet. Kann es sein, dass der Besucher, wenn er ungeduldig ist, das CGI gerade wärend des schreibens abbricht??? Das ist halt meine Vermutung, da ich sonst keine Idee habe was es sein könnte!

Bitte helft mir! Wäre mir sehr wichtig!
Danke

  1. hallo arno,
    ich erlaubbe mir auf die self html forums faq zu verweisen

    http://forum.de.selfhtml.org/faq/#Q-07

    so kann dir schlecht jemand helfen ohne quelltext.

    mfg
    sven

    1. Sorry! Hier also der Source Code. Ich hoffe ihr kennt euch aus, hab ein bischen unschän programmiert befürchte ich. Vielleicht ist mir ja trotzdem noch zu helfen ;o)

      #!/usr/bin/perl

      use CGI qw(:standard);

      @Spiele = ("");    # Speicher für alle Datensaetze
      @Datensatz = ("");   # Speicher für alle Felder des aktuellen Datensatzes
      @Stat2 = ("");

      $Jetztwert = time();
      $Jetztzeit = localtime($Jetztwert);
      @Zeit = split(/ +/,$Jetztzeit);
      @Uhrzeit = split(/:/,$Zeit[3]);

      #------------- Einlesen der Daten ------------
      open(SPIELE, "<spiele.txt") || die "Spieledatei nicht gefunden\n";
      while(<SPIELE>)
       {
        if($i == 0)
         {
          $Felder = $_;
         }
        else
         {
          $Spiele[$i] = $_;
         }
        $i++;
       }
      close(SPIELE);
      chop($Felder);
      @Datenfelder = split(/ƒ/,$Felder);

      #------------- Einlesen der Statistikdatei ------------
      $i=0;
      open(STAT2, "<stat2.txt") || die "Statistikdatei nicht gefunden\n";
      while(<STAT2>)
       {
        $Stat2[$i] = $_;
        $i++;
       }
      close(STAT2);

      #------------- Schreiben der Statistiksatei ------------
      $i=0;
      open(STAT2, ">stat2.txt") || die "Statistikdatei 2 nicht gefunden\n";

      for(@Stat2)                        # solange Daten in der Adressenliste sind
      {
          @StatDatensatz2 = split(/ƒ/,$_);         # Aktuellen Datensatz aufdröseln
       if ($StatDatensatz2[0] ne "123") {
           if ($i>0) {
         print STAT2 ("\n");
        }

      print STAT2 $StatDatensatz2[0];print STAT2 "ƒ";
        print STAT2 $StatDatensatz2[1];print STAT2 "ƒ";
         print STAT2 $StatDatensatz2[2];print STAT2 "ƒ";
        print STAT2 $StatDatensatz2[3];print STAT2 "ƒ";
        print STAT2 $StatDatensatz2[4];print STAT2 "ƒ";
        print STAT2 $StatDatensatz2[5];print STAT2 "ƒ";
        print STAT2 $StatDatensatz2[6];print STAT2 "ƒ";
        print STAT2 $StatDatensatz2[7];print STAT2 "ƒ";
        print STAT2 $StatDatensatz2[8];print STAT2 "ƒ";
        print STAT2 $StatDatensatz2[9];print STAT2 "ƒ";
        print STAT2 $StatDatensatz2[10];print STAT2 "ƒ";
        print STAT2 $StatDatensatz2[11];print STAT2 "ƒ";

      }
      $i++;
      }

      Statistik Datei bleibt noch offen, weil noch etwas dazugeschrieben wird!

      &menu;

      for(@Spiele)
       {
        @Datensatz = split(/ƒ/,$_);
        $i = 0;
        if ($Datensatz[0] eq param('Spiel')){

      #Neuer Statistikeintrag -----------
       print STAT2 "\n"; print STAT2 "$Datensatz[0]ƒ$Datensatz[1]ƒ1ƒ$Zeit[0]ƒ$Zeit[1]ƒ$Zeit[2]ƒ$Zeit[3]ƒ";
       print STAT2 $ENV{'REMOTE_ADDR'};print STAT2 "ƒ";
       print STAT2 $ENV{'REMOTE_HOST'};print STAT2 "ƒ";
       print STAT2 $ENV{'REMOTE_USER'};print STAT2 "ƒ";
       print STAT2 $ENV{'HTTP_REFERER'};print STAT2 "ƒ";
       print STAT2 $ENV{'HTTP_ACCEPT_LANGUAGE'};print STAT2 "ƒ";

      close(STAT2);

      #ENDE Neuer Statistikeintrag -----------

      usw usw usw

      Hier folgt dann noch die HTML Ausgabe

      1. Hi Arno,

        versuche mal, geistig einen Schritt weg von der konkreten Lösung zu
        machen - das ganze Perl ist mir alles viel zu konkret.

        Du liest Daten aus einer Datei ein und schreibst anschließend Daten
        in dieselbe Datei zurück. Wenn das mehrere Besucher gleichzeitig tun,
        dann bekommst Du Probleme.

        Ich würde die Sache also auf einer wesentlich abstrakteren Ebene angehen:

        • Brauchst Du die gelesenen Daten, um neue zu schreiben? (Würde es nicht
            reichen, die Datei nur zum Erweitern zu öffnen, also neue Daten hinten
            dran zu hängen? Das wäre zumindest schon mal deutlich performanter.)
        • Machst Du in Deiner Datei eine Art Vorverarbeitung, welche den lesenden
            Zugriff erfordert? Könntest Du statt dessen erst mal nur Rohdaten er-
            fassen und die Auswertung davon völlig abtrennen?
        • Müssen die Daten verschiedener Benutzer unbedingt in derselben Datei
            gespeichert werden? (Wenn nein, entfällt der Aufwand, die Zugriffe
            synchronisieren zu müssen.)
          All dies gehört in den Bereich "Architektur" Deiner Anwendung. Vielleicht
          fällt Dir auf, daß nichts von meinen Angaben irgendwas mit einer konkreten
          Programmiersprache zu tun hat - das sollte alles geklärt sein, lange bevor
          Du Dich für eine entsprechende Implementierungssprache entscheidest.

        Richtiges Programmieren ist etwas mehr, als ein paar Befehle hinzuschreiben.

        Viele Grüße
              Michael

        1. Hallo!

          Nun ja, ich möchte eine Statistik für meine Homepage machen. Also wenn wir mal nur davon ausgehen, dass ich die Besucheranzahl erhöhen will, so muss ich den aktuellen Stand zuerst auslesen, dann bearbeiten (eins erhöhen) und wieder abspeichern.

          d.h. für die Architektur:
          ad 1.) Ja ich brauche die Daten der Datei um "neue" zu schreiben. Ein anhängendes Schreiben kommt also nicht in Frage.

          ad. 2) Wie gesagt: Ich öffne die Datei (lesen) und lese mal alle Daten aus. Ich schließe die Datei.

          Ich verändere alle Daten die ich ändern will (z.B. Besucheranzahl)

          Ich öffne die Datei (schreiben) und schreibe alle Datei in die Datei. Ich schließe die Datei.

          ad 3.) Ja alle Benutzer müssen auf die selbe Datei zugreifen.

          lg
          Arno

          1. Hi Arno,

            Nun ja, ich möchte eine Statistik für meine Homepage machen.

            Warum willst Du dafür die Zugriffe selbst erfassen?

            Reichen Dir die Informationen nicht, welche Dein Webserver bereits erfaßt?
            (http://webalizer.teamone.de/selfforum/)

            Viele Grüße
                  Michael

  2. Huhu Arno

    das riecht irgendwie nach mit-ohne-file-locking gekocht, oder?

    Viele Grüße

    lulu

    Das Problem ist jetzt, dass irgendwie das File verhundst wird auch wenn alles zu gehen scheint. Gestern hatte ich 260 Zeilen (Da 260 Besucher), heute hatte ich dann nur mehr 130! Der rest war verschwunden. Da haut also was mit aulesen, verändern und wieder schreiben nicht hin.

    1. File locking klingt gut! :o)
      Hab ich nicht gemacht! Habs einfach geöffnet, offen gelassen so lang ichs brauch, geschrieben und dann geschlossen.

      Okay, ich werd mal selfhtml durchforsten, da steht sich was über filelocking drinnen nehm ich an!

      vielen Dank vorerst

      Huhu Arno

      das riecht irgendwie nach mit-ohne-file-locking gekocht, oder?

      Viele Grüße

      lulu

      Das Problem ist jetzt, dass irgendwie das File verhundst wird auch wenn alles zu gehen scheint. Gestern hatte ich 260 Zeilen (Da 260 Besucher), heute hatte ich dann nur mehr 130! Der rest war verschwunden. Da haut also was mit aulesen, verändern und wieder schreiben nicht hin.

      1. Die Zeilen beim öffnen der Datei sehen nun so aus:

        open(STAT2, "<stat2.txt") || die "Statistikdatei nicht gefunden\n";
        flock(STAT2, LOCK_EX);

        Ich hoffe das behebt mein Problem!

        1. Hoi,

          Die Zeilen beim öffnen der Datei sehen nun so aus:

          open(STAT2, "<stat2.txt") || die "Statistikdatei nicht gefunden\n";
          flock(STAT2, LOCK_EX);

          Ich hoffe das behebt mein Problem!

          Nein, wird es nicht. Wenn der User auf ESC drueckt, kann es durchaus
          sein, dass das Script terminiert wird, bevor es fertig ist mit
          schreiben. Siehe dazu auch

          http://forum.de.selfhtml.org/archiv/2002/1/2616/

          Gruesse,
           CK

          1. Okay, also in der theorie hab ich deine ausführliche Erklärung halbwegs verstanden!

            Aber wo gehört ...

            my $pid = fork;
            unless($pid) {
              die 'could not fork!' unless defined $pid;
              # process is no longer a child
              die 'could not remove session' unless setsid;
            }
            else {
              # main process ends
              exit 0;
            }

            nun genau hin? Im Source Code mein ich?

            Ist wahrscheinlich eine blöde Frage oder? Sorry!

            1. Hoi, <-- Begruessung

              Okay, also in der theorie hab ich deine ausführliche Erklärung
              halbwegs verstanden!

              Gut.

              Aber wo gehört ...

              my $pid = fork;
              unless($pid) {
                die 'could not fork!' unless defined $pid;
                # process is no longer a child
                die 'could not remove session' unless setsid;
              }
              else {
                # main process ends
                exit 0;
              }

              nun genau hin? Im Source Code mein ich?

              Unter die letzte Ausgabe. Das Schreiben musst du halt zuletzt machen.

              Ist wahrscheinlich eine blöde Frage oder? Sorry!

              Es gibt keine bloeden Fragen, hoechstens ueberfluessige. Und diese
              wars nicht.

              Gruesse,
               CK