Candid Dauth: Zeile aus Datei entfernen, ohne Datei einlesen zu müssen.

Heißa, Forum,

ich habe eine Datei, in der zeilenweise Werte drinstehen:

bla  
moep  
blubb  
gautera  
[…]

Nun soll ein PHP-Skript folgendes machen:
Es soll eine zufällige Zeile finden, deren Wert benutzen und die Zeile dann aus der Datei löschen, damit der Wert kein zweites Mal benutzt wird.

Das Problem ist nun, dass die Datei ziemlich groß ist (mehrere MB) und ich sie deshalb nicht komplett in den Speicher laden will. Eine zufällige Zeile herauszufinden ist nun kein Problem, ich nehme einfach an eine zufällige Position in der Datei (ermittelt per rand() und filesize()) und suche dann den nächstbesten Zeilenumbruch. Das Problem ist aber das Löschen der Zeile.

Im Chat habe ich mir sagen lassen, dass PHP hierfür keine Boardmittel mitbringt. Also wurde mir empfohlen, die Datei Stück für Stück auszulesen, auf diese Weise den Inhalt in eine andere Datei zu kopieren – bis eben auf die Zeile – und dann die Original-Datei mit der neuen zu überschreiben.

Das gefällt mir nur nicht ganz, denn es kann sein, dass das Script ziemlich oft aufgerufen wird, und das würde den Server recht stark belasten, wenn er ständig mehrere MB hin- und herkopieren müsste, nur um eine Zeile aus der Datei zu löschen.

Hat jemand von euch eine Idee, wie man das schön performant lösen könnte?

Gautera!
Grüße aus Biberach Riss,
Candid Dauth

--
Ein Fußball-Fan? Noch auf der Suche eine Schlafmöglichkeit im Großraum Stuttgart für die WM 2006? Wie wäre es mit Herrenberg, einer gemütlichen Kleinstadt am Rande des Schönbuchs? – Von der Lage her ideal, auch für andere Vorhaben im Urlaub. Ferienwohnungen-Herrenberg.com.
http://cdauth.de/
  1. Hi,

    Es soll eine zufällige Zeile finden, deren Wert benutzen und die Zeile dann aus der Datei löschen, damit der Wert kein zweites Mal benutzt wird.

    Das Problem ist nun, dass die Datei ziemlich groß ist (mehrere MB) und ich sie deshalb nicht komplett in den Speicher laden will. Eine zufällige Zeile herauszufinden ist nun kein Problem, ich nehme einfach an eine zufällige Position in der Datei (ermittelt per rand() und filesize()) und suche dann den nächstbesten Zeilenumbruch. Das Problem ist aber das Löschen der Zeile.

    Nur mal so als Idee:
    Erweitere die Suche nach dem nächsten Zeilenumbruch etwas, nämlich um die Suche nach dem nächsten Zeilenumbruch, dem kein weiterer Zeilenumbruch folgt.
    Zum Löschen überschreibst Du dann die benutzte Zeile mit lauter Zeilenumbruchzeichen.
    (wahlweise auch mit einem anderen, sonst nicht benutzten Zeichen überschreiben, dann halt die Suche nach der Zeile entsprechend anpassen)

    Im Chat habe ich mir sagen lassen, dass PHP hierfür keine Boardmittel mitbringt. Also wurde mir empfohlen, die Datei Stück für Stück auszulesen, auf diese Weise den Inhalt in eine andere Datei zu kopieren – bis eben auf die Zeile – und dann die Original-Datei mit der neuen zu überschreiben.

    Ist nicht so sehr ein PHP- wie ein Dateisystem-Problem: man kann nicht einfach mitten in einer Datei etwas rauslöschen.

    cu,
    Andreas

    --
    Warum nennt sich Andreas hier MudGuard?
    Schreinerei Waechter
    Fachfragen per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
    1. Heißa, MudGuard,

      Erweitere die Suche nach dem nächsten Zeilenumbruch etwas, nämlich um die Suche nach dem nächsten Zeilenumbruch, dem kein weiterer Zeilenumbruch folgt.
      Zum Löschen überschreibst Du dann die benutzte Zeile mit lauter Zeilenumbruchzeichen.

      Okay, vielen Dank, so habe ich es jetzt gelöst. Ist zwar ein klein wenig umständlich, aber es funktioniert. :-)

      Gautera!
      Grüße aus Biberach Riss,
      Candid Dauth

      --
      Ein Fußball-Fan? Noch auf der Suche eine Schlafmöglichkeit im Großraum Stuttgart für die WM 2006? Wie wäre es mit Herrenberg, einer gemütlichen Kleinstadt am Rande des Schönbuchs? – Von der Lage her ideal, auch für andere Vorhaben im Urlaub. Ferienwohnungen-Herrenberg.com.
      http://cdauth.de/
      1. echo $begrüßung;

        Erweitere die Suche nach dem nächsten Zeilenumbruch etwas, nämlich um die Suche nach dem nächsten Zeilenumbruch, dem kein weiterer Zeilenumbruch folgt.
        Zum Löschen überschreibst Du dann die benutzte Zeile mit lauter Zeilenumbruchzeichen.

        Okay, vielen Dank, so habe ich es jetzt gelöst. Ist zwar ein klein wenig umständlich, aber es funktioniert. :-)

        Mit dieser Methode suchst du dir mit zunehmenden Lösch-Überschreiben einen Wolf. Und wenn deine Zufallszahl hinter der letzten noch lebenden Zeile landet, dann findest du nichts mehr, obwohl ja doch noch was da ist.

        Aber eine vernünftige dateibasierte Lösung fällt mir auch nicht ein, nur "Datenbank" kommt mir in den Sinn. Es muss ja nicht immer MySQL sein, es gibt da ja auch noch die Database (dbm-style) Abstraction Layer Functions, die ganz einfache Key-Value-Beziehungen verwalten können.

        echo "$verabschiedung $name";

        1. Heißa, dedlfix,

          Mit dieser Methode suchst du dir mit zunehmenden Lösch-Überschreiben einen Wolf. Und wenn deine Zufallszahl hinter der letzten noch lebenden Zeile landet, dann findest du nichts mehr, obwohl ja doch noch was da ist.

          Och, das habe ich schon hinbekommen. Wenn bis zum Ende der Datei nichts gefunden wird, wird vom Anfang an weitergesucht (eigentlich umgekehrt, es wird rückwärts nach Zeilenenden gesucht). Wenn überhaupt nichts gefunden wird, wird abgebrochen.
          Klar, dann lese ich wieder die ganze Datei ein, aber wenn ich es so mache, wie Daniel es vorgeschlagen hat, dass die Datei einmal am Tag „geleert“ wird, ist das auch nicht mehr so problematisch.

          Aber eine vernünftige dateibasierte Lösung fällt mir auch nicht ein, nur "Datenbank" kommt mir in den Sinn. Es muss ja nicht immer MySQL sein, es gibt da ja auch noch die Database (dbm-style) Abstraction Layer Functions, die ganz einfache Key-Value-Beziehungen verwalten können.

          Hm, mir gefallen Textdateien besser. Über Datenbanken habe ich auch schon nachgedacht, aber bei meinem Webhoster steht mir nur MySQL zur Verfügung, und irgendwie kann ich das nicht leiden.
          Deinen Link werde ich mir später noch anschauen, vielleicht ist das ja doch was.

          Gautera!
          Grüße aus Biberach Riss,
          Candid Dauth

          --
          Ein Fußball-Fan? Noch auf der Suche eine Schlafmöglichkeit im Großraum Stuttgart für die WM 2006? Wie wäre es mit Herrenberg, einer gemütlichen Kleinstadt am Rande des Schönbuchs – von der Lage her ideal, auch für andere Vorhaben im Urlaub. Ferienwohnungen-Herrenberg.com.
          http://cdauth.de/
        2. echo $begrüßung;

          Database (dbm-style) Abstraction Layer Functions, die ganz einfache Key-Value-Beziehungen verwalten können.

          Wenn ich nochmal so darüber nachdenke, sind die auch nicht so sehr geeignet, da man nach dem Löschen Lücken in den Keys hat. Man kann die nicht ohne Aufwand neu nummerieren. Damit wird der Zugriff wieder zum Glücksspiel. :-(

          echo "$verabschiedung $name";

  2. Ahoi Candid Dauth,

    Hat jemand von euch eine Idee, wie man das schön performant lösen könnte?

    nach reiflicher prüfung der Funktionen des Dateisystems
    Komme ich zu folgendem ergebniss:

    • öffne die datei mit fopen()
    • gehe an irgendeine stelle und merke dir die position des Dateizeigers.
    • ließ den wert aus
    • überschreibe ihn mit fputs() mit einem absurden wert (alla ######benutzt#####)
    • Durchlaufen z.B. täglich die datei und lösche durch umschreiben usw. die ##########benutzt######### zeilen.

    PS: zu deiner Signutar, ich bin Badner, kein Fussballfan und suche
    deshalb keine Übernachtungsmöglichkeit im Großraum Stuttgart.

    MfG

    --
    Alle Angaben wie immer ohne Gewähr
    1. Heißa, Daniel,

      PS: zu deiner Signutar, ich bin Badner, kein Fussballfan und suche
      deshalb keine Übernachtungsmöglichkeit im Großraum Stuttgart.

      Aha, und warum erzählst du mir das? ;-)

      Gautera!
      Grüße aus Biberach Riss,
      Candid Dauth

      --
      Ein Fußball-Fan? Noch auf der Suche eine Schlafmöglichkeit im Großraum Stuttgart für die WM 2006? Wie wäre es mit Herrenberg, einer gemütlichen Kleinstadt am Rande des Schönbuchs – von der Lage her ideal, auch für andere Vorhaben im Urlaub. Ferienwohnungen-Herrenberg.com.
      http://cdauth.de/
  3. Hello,

    den Inhalt einer Datei zu lesen, ohne die Datei einzulesen ist nicht möglich.
    Den Inhalt einer sequentiellen Datei mit freier Satzlänge zu ändern, speziell eine Zeile zu entfernen, ist nicht möglich, ohne die Datei umzukopieren.

    Diese Aussagen beziehen sich immer auf die üblichen DO-Systeme.

    Selbstverständlich gab es auch schon viele andere, die sich nicht durchsetzen konnten und gibt es auch noch ein paar andere für Spezialanwendungen, die dann aber auch teuer sind. Dabei ist das meiste daran heute nur noch Software...

    Wenn Du hingegen eine Datei mit fester Satzlänge baust, kannst Du auf Datensätze über ihre physische Position (pseudo-physische Position) direkt zugreifen, sie ggf. als "gelöscht" markieren oder ihren Inhalt verändern. Das ist dann wahlfreier Zugriff auf den Satz.

    Wenn es Dir also um Geschwindigkeit, und nicht um Datenmenge geht, dann solltest Du Dateien mit fester Satzlänge schreiben.

    Harzliche Grüße vom Berg
    esst mehr http://www.harte-harzer.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau