Pit: Große Datei einlesen will nicht (php)

Hallo,

ich möchte eine Datei einlesen, die knapp 24MB Daten enthält.

<?php
//-----------------------------------------------------
// Datei einlesen
//-----------------------------------------------------
$filename = "e_test.txt";
if ( ! $arr_file = file( $filename ) ) {
    echo "Fatal: '$filename' konnte nicht gelesen werden.";
    trigger_error( "'$filename' konnte nicht gelesen werden.", E_USER_ERROR );
}
//-----------------------------------------------------
// Zeilen ausgeben
//-----------------------------------------------------
foreach ($arr_file AS $zeile) {
echo $zeile."<br>";
}

als Antwort erhalte ich:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 36 bytes) in F:\xampplite ...

Beziehen sich die 134217728 bytes auf den Arbeitsspeicher? Denn die Datei ist es ja nicht.

Pit

  1. Tach!

    Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 36 bytes) in F:\xampplite ...
    

    Beziehen sich die 134217728 bytes auf den Arbeitsspeicher? Denn die Datei ist es ja nicht.

    Das bezieht sich auf den erlaubten Arbeitsspeicher gemäß der Konfiguration memory_limit. Die Datei selbst ist nicht so groß, aber PHP hält keine 1:1-Kopie davon im Speicher, sondern die Funktion file() erzeugt ein Array mit je einer Zeile als String daraus. Das belegt dann durchaus mehr Speicher.

    dedlfix.

    1. Hi dedlfix,

      Das bezieht sich auf den erlaubten Arbeitsspeicher gemäß der Konfiguration memory_limit. Die Datei selbst ist nicht so groß, aber PHP hält keine 1:1-Kopie davon im Speicher, sondern die Funktion file() erzeugt ein Array mit je einer Zeile als String daraus. Das belegt dann durchaus mehr Speicher.

      Ok, verstehe. Hintergrund ist der, dass in der Datei Tabellendaten stehen, die ich in eine DB einlesen möchte. Die Datei ist zwar eine .xls Datei, aber das scheint nur die Endung zu sein. In die Datei mal hineingeschaut sieht man sehr schnell, dass es sich um eine html-Tabelle handelt, die jeden Datensatz als Tabellenzeile mitsamt 10 oder 11 Tabellenspalten beinhaltet.

      Als reine Exceltabelle würde die Datei vielleicht nichtmal 1MB haben, aber in eine html-Tabelle verpackt, ergibt das knapp 24MB 😟

      Dann muß ich da wohl mit fopen/fgets ran.

      Bleibt trotzdem die Frage, ob ich im weiteren verlauf die Datei mit php verarbeitet bekommen.

      Pit

      1. Lieber Pit,

        dass es sich um eine html-Tabelle handelt, die jeden Datensatz als Tabellenzeile mitsamt 10 oder 11 Tabellenspalten beinhaltet.

        kann man die mit simplexml_load_file() parsen und einlesen, oder hagelt es auch wieder diesen Fehler?

        Als SimpleXML-Objekt könntest Du das Dokument leichter verarbeiten, daher lohnt sich vielleicht der Aufwand, bevor Du mit fgets & co. zu Werke schreitest.

        Liebe Grüße,

        Felix Riesterer.

        1. Hallo Felix,

          kann man die mit simplexml_load_file() parsen und einlesen, oder hagelt es auch wieder diesen Fehler?

          Als SimpleXML-Objekt könntest Du das Dokument leichter verarbeiten, daher lohnt sich vielleicht der Aufwand, bevor Du mit fgets & co. zu Werke schreitest.

          Ich bin inzwischen schon fertig mit der Datei.

          Ich habe sie mir zunächst über exec split ... in 12 kleinere dateien zerteilt, diese danach über ein Script aufgerufen, das sich immer wieder selber neu aufruft und die nächste Datei nimmt (bis !file_exists true meldet) und die je Durchlauf behandelten Daten in eine neue Datei schreibt.

          So wird aus der 24MB Datei letztlich eine 5,8MB große datei mit pipe-getrennten Daten, die ich widerum gut in eine db einlesen kann.

          Danke trotzdem für den Tip.

          Pit

          Folgende Beiträge verweisen auf diesen Beitrag:

  2. Gibt es einen Grund das über den Webserver laufen zu lassen? MfG

    1. Gibt es einen Grund das über den Webserver laufen zu lassen? MfG

      Prinzipiell nicht. Welche Alternative schwebt Dir vor?

      Pit

      1. Gibt es einen Grund das über den Webserver laufen zu lassen? MfG

        Prinzipiell nicht. Welche Alternative schwebt Dir vor?

        Lass dein PHP Script auf der Kommandozeile laufen. MfG

        1. Lass dein PHP Script auf der Kommandozeile laufen. MfG

          Aha? habe ich noch nie gemacht. Wie geht das und welchen Vorteil habe ich dadurch?

          Pit

          1. #php script.php

            Braucht weniger Ressourcen. MfG

            1. #php script.php

              Braucht weniger Ressourcen. MfG

              Cool, werde ich ausprobieren, danke.

              Pit

              1. Mach das mal. Ein Webserver ist hier nämlich völlig unnötig und Du kannst Dich in Deinem Script auf das Wesentliche beschränken und musst auch kein HTML ausgeben. Idealerweise hast Du einen Editor der mit RegEx'n derart umgehen kann, daß er im Falle eines Fehlers bei der Ausführung von selbst auf die betroffene Zeile springt (und ggf. auch die includete Datei dazu lädt). MfG

                1. Hallo pl,

                  Mach das mal. Ein Webserver ist hier nämlich völlig unnötig und Du kannst Dich in Deinem Script auf das Wesentliche beschränken und musst auch kein HTML ausgeben.

                  Seit wann muss man HTML ausgeben, wenn man einen Webserver verwenden möchte?

                  Bis demnächst
                  Matthias

                  --
                  Pantoffeltierchen haben keine Hobbys.
                  1. Seit wann muss man HTML ausgeben, wenn man einen Webserver verwenden möchte?

                    Seit wann braucht man einen Webserver wenn man Dateien verarbeiten möchte?

                    Und was meinen Hinweis auf den Editor betrifft der Code ausführen kann: Das ist auch beim Entwickeln von Webanwendungen nützlich. Und noch komfortabler wirds wenn der Editor den Code gleich hochladen kann.

                    MfG

            2. Tach!

              #php script.php

              Braucht weniger Ressourcen.

              Wohl eher nicht. Lediglich das, was durch die Interaktion mit dem Webserver benötigt wird, fällt weg. Ansonsten arbeitet PHP am CLI auch nicht grundlegend anders als im Webserver, so dass "weniger Ressourcen" kein entscheidendes Kriterium ist. Wenn das memory_limit genauso eingestellt ist, beendet sich PHP auch am CLI mit derselben Fehlermeldung.

              dedlfix.

      2. Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 36 bytes) in F:\xampplite …

        Welche Alternative schwebt Dir vor?

        memory_limit = 128M
        

        in .htaccess überschreiben:

        php_value memory_limit 256M
        

        oder (wenn das nicht erlaubt sein sollte) erst den Name der user.ini herausbekommen:

        grep 'user_ini' /etc/php/7.3/apache2/php.ini
        

        (der Pfad kann abweichen, notfalls mit phpinfo() ermitteln ) liefert:

        ;user_ini.filename = ".user.ini"
        

        Dann kannst Du im Arbeitsverzeichnis also eine Datei mit dem Name '.user.ini' anlegen, für jeden lesbar machen und

        memory_limit = 256M
        

        hineinschreiben. Für PHP als CLI (in der Konsole oder ssh-Sitzung) wird aber die Datei /etc/php/7.3/cli/php.ini verwendet.

        Bei einmaliger Anwendung sollten auch 512MB oder 4096MB oder -1 (kein Limit!) unproblematisch sein. Also so lange der Speicher dafür reicht…

        Folgende Beiträge verweisen auf diesen Beitrag:

        1. Tach!

          [...] F:\xampplite …

          grep 'user_ini' /etc/php/7.3/apache2/php.ini
          

          grep ist kein Programm, das ohne weiteres in Windows verfügbar ist.

          hineinschreiben. Für PHP als CLI (in der Konsole oder ssh-Sitzung) wird aber die Datei /etc/php/7.3/cli/php.ini verwendet.

          Auch gibt es bei einer XAMPP-Installation einen solchen Pfad nicht.

          dedlfix.

          1. Auch gibt es bei einer XAMPP-Installation

            Hab ich doch was vergessen:

            • Kein Windows + XAMPP benutzen.

            Grund: Wer macht denn SOWAS?

            1. Tach!

              Auch gibt es bei einer XAMPP-Installation

              Hab ich doch was vergessen:

              • Kein Windows + XAMPP benutzen.

              Was konkret ändert das in Bezug auf den Fehler, das nicht auch unter Windows entsprechend konfiguriert werden kann?

              dedlfix.

              1. Was konkret ändert das in Bezug auf den Fehler,

                Hier dürfen auch allgemeine Ratschläge geäußert werden, die nicht unbedingt das aktuelle Problem lösen aber künftige zu vermeiden helfen.

                Darüber hinaus lässt Linux mehr vom Arbeitsspeicher für die Anwendungen übrig...

                grep ist Bestandteil der Unix-Tools für Windows (Direktdownload). (Alle Dateien in zip:/wbin/ einfach nach c:\windows\ entpacken...)

                1. Tach!

                  Hier dürfen auch allgemeine Ratschläge geäußert werden, die nicht unbedingt das aktuelle Problem lösen aber künftige zu vermeiden helfen.

                  Du meinst, wenn man einen kompletten Betriebssystemwechsel vornimmt, ergeben sich nicht tausend neue Probleme mit dem unbekannten System?

                  Ich wüsste grad nicht, welche typischen PHP-Fehler windows-spezifisch und so gravierend sind, dass man mit einem anderen System grundsätzlich besser fahren würde. Man darf bei allgemeinen Ratschlägen durchaus auch die Verhältnismäßigkeit in Betracht ziehen.

                  grep ist Bestandteil der Unix-Tools für Windows (Direktdownload). (Alle Dateien in zip:/wbin/ einfach nach c:\windows\ entpacken...)

                  Die unter Windows bessere Vorgehensweise ist, die Datei im Texteditor zu öffnen und dessen Suchfunktion zu verwenden. Dann ist man außerdem gleich an Ort und Stelle, um Änderungen vorzunehmen.

                  Da es sich aber um eine XAMPP-Installation handelt, kann man auch gleich direkt die php.ini bearbeiten, ohne sich zur .user.ini durchsuchen zu müssen.

                  dedlfix.

                  1. Dann ist man außerdem gleich an Ort und Stelle, um Änderungen vorzunehmen.

                    Nicht Dein Ernst oder?

                    sed ist auch bei den Unix-Tools dabei.

                    Ich empfehle Pit, die Krücken wegzuwerfen, weil er sie nicht braucht und sich also an "richtiges Gehen" zu gewöhnen. Du sagst, er soll sie behalten und weiter damit rumstolpern.

                    1. Ich empfehle Pit, die Krücken wegzuwerfen, weil er sie nicht braucht und sich also an "richtiges Gehen" zu gewöhnen.

                      Fein.

                      Du sagst, er soll sie behalten und weiter damit rumstolpern.

                      Nee. Er orientiert sich an den Gegebenheiten, Gunnar. Äh, Ursus, Äh, Jörg.

                2. (Unix-Tools)

                  split ist auch dabei, damit kann man Textdateien in Stücke zu maximal X Zeilen aufteilen.

                  Dann wäre da noch gawk. Ein tolles Tool, welches PIT auch bei dem anderen Problem helfen könnte...

                  1. (Unix-Tools)

                    split ist auch dabei, damit kann man Textdateien in Stücke zu maximal X Zeilen aufteilen.

                    Dann wäre da noch gawk. Ein tolles Tool, welches PIT auch bei dem anderen Problem helfen könnte...

                    Hi Ursus,

                    Ja, split habe ich auch hergenommen…

                    Pit

              2. Nun ja. Schauen wir mal. Originale Datei mit einer Änderung: Der Dateiname:

                <?php
                //-----------------------------------------------------
                // Datei einlesen
                //-----------------------------------------------------
                $filename = "test.txt";
                if ( ! $arr_file = file( $filename ) ) {
                    echo "Fatal: '$filename' konnte nicht gelesen werden.";
                    trigger_error( "'$filename' konnte nicht gelesen werden.", E_USER_ERROR );
                }
                //-----------------------------------------------------
                // Zeilen ausgeben
                //-----------------------------------------------------
                foreach ($arr_file AS $zeile) {
                echo $zeile."<br>";
                }
                

                memory_limit ist auf 128MB gesetzt:

                grep memory_limit /etc/php/7.2/cli/php.ini 
                memory_limit = 128M 
                

                Datei ist 24 MB groß:

                ls -s -h test.txt 
                24M test.txt
                

                Run!

                php test.php | wc -c
                27464320
                

                Fazit: Auf Grund des allgemein mehr Speicher fressenden Umgangs von Windows (PHP unter Windows benutzt natürlich die Windows-Libs) wird von PHP unter Unixoiden für die Funktion file() weniger Speicher gebraucht, so dass die selbe Operation, die unter Windows am identischen Speicherlimit scheiterte, unter Linux störungsfrei durchläuft.