Riesige Dateien in PHP zeilenweise lesen, ohne den Server zu überlasten

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: „Fataler Fehler“ und 2 Gigabyte Logs



Stellen Sie sich vor: Sie sind Entwickler und ein Systemadministrator kommt mit einem USB-Stick zu Ihnen. Darauf befindet sich die Logdatei des Webservers der letzten sechs Monate. Die Größe? Bescheidene 2,5 Gigabyte. „Ich muss alle IP-Adressen finden, von denen Brute-Force-Versuche kamen“, sagt er und geht Kaffee trinken.



Sie öffnen die IDE und schreiben automatisch:

$lines = file('huge_log.txt');foreach ($lines as $line) {    // parsen...}

Sie drücken „Start“... und sehen im Browser einen weißen Bildschirm, während in den Fehlerlogs Fatal Error: Allowed memory size exhausted erscheint. Kommt Ihnen bekannt vor? Das ist die klassische Falle, in die fast alle PHP-Entwickler schon einmal getappt sind.



Die Frage „How to read a large file line by line?“ auf Stack Overflow hat nicht ohne Grund Hunderttausende von Aufrufen. Es ist eine dieser Aufgaben, bei denen die „naive“ Lösung den Server killt, während der richtige Ansatz das Projekt rettet. Heute analysieren wir, wie man riesige Dateien in PHP liest, ohne das Speicherlimit zu überschreiten und dabei hohe Leistung beizubehalten. Los geht's!



Warum file() und file_get_contents() das Böse für große Datenmengen sind



Lassen Sie uns gleich den größten Mythos entkräften. Die Funktionen file() und file_get_contents() sind gierige Funktionen. Sie laden die gesamte Datei auf einmal in den Arbeitsspeicher. Wenn Ihre Datei 2 GB wiegt und das memory_limit in der php.ini auf 128 MB gesetzt ist (Standardwert für viele Hostings), erhalten Sie garantiert einen Fehler.



Darüber hinaus speichert PHP Zeichenketten in einer Kodierung, die den Speicherverbrauch im Vergleich zur Dateigröße auf der Festplatte um das 2- bis 4-fache erhöhen kann. Das bedeutet, dass 2 GB Logs 6-8 GB RAM verbrauchen können!



Fazit: Wenn die Dateigröße 10-20 % Ihres memory_limit überschreitet, vergessen Sie file(). Wir brauchen einen Streaming-Ansatz.



Der richtige Weg: fgets() und Streaming-Lesen



Die zuverlässigste und leistungsfähigste Methode ist die Verwendung von fopen() in Kombination mit fgets(). Diese Funktionen lesen die Datei nicht vollständig, sondern Zeile für Zeile. Stellen Sie sich vor, Sie trinken Saft durch einen Strohhalm – Sie trinken nicht das ganze Glas auf einmal, sondern schlürfen nach und nach. Genauso funktioniert Streaming-Lesen.



Hier ist ein einfaches, aber funktionierendes Beispiel:



<?php$handle = fopen('huge_log.txt', 'r');if ($handle) {    while (($line = fgets($handle)) !== false) {        // Eine Zeile verarbeiten        echo $line;    }    fclose($handle);}?>


Was passiert hier? fopen() öffnet die Datei und gibt einen Zeiger (resource) zurück. fgets() liest jedes Mal eine Zeile bis zum Zeilenumbruch (). Speicher wird nur für die aktuelle Zeile reserviert, nicht für die gesamte Datei. Nach der Verarbeitung wird die Zeile vom Garbage Collector zerstört (oder überschrieben).



Wichtige Leistungsnuancen

  • Puffergröße: fgets() liest standardmäßig bis zu 8192 Bytes auf einmal. Wenn Zeilen länger sind, führt die Funktion mehrere Iterationen durch. Für die allermeisten Logs ist das ausreichend.
  • Prüfung auf false: Verwenden Sie immer den strikten Vergleich !== false. Warum? Weil eine Zeile leer ("") sein oder "0" enthalten kann und while ($line = fgets($handle)) vorzeitig anhalten könnte.
  • Datei schließen: Rufen Sie immer fclose() auf. Ja, PHP macht das automatisch am Ende des Skripts, aber wenn Sie die Datei in einer Schleife oder in einem Hintergrundskript verarbeiten, sind nicht geschlossene Deskriptoren ein Ressourcenleck.


Super-Ladung: Generatoren (yield) zur Wiederverwendung



Manuelles fopen/fclose-Management ist gut, aber wenn Sie verschiedene Dateien in verschiedenen Teilen des Projekts lesen müssen, beginnt sich der Code zu wiederholen. Hier kommen Generatoren zur Hilfe – eine der elegantesten Funktionen von PHP.



Ein Generator ermöglicht es Ihnen, eine Funktion zu erstellen, die

Blogs

Buchempfehlungen