Große Datei einlesen will nicht (php)
Pit
- php
0 dedlfix0 Pit0 Felix Riesterer0 Pit
0 pl0 Pit
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
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.
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
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.
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
Gibt es einen Grund das über den Webserver laufen zu lassen? MfG
Gibt es einen Grund das über den Webserver laufen zu lassen? MfG
Prinzipiell nicht. Welche Alternative schwebt Dir vor?
Pit
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
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
#php script.php
Braucht weniger Ressourcen. MfG
#php script.php
Braucht weniger Ressourcen. MfG
Cool, werde ich ausprobieren, danke.
Pit
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
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
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
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.
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…
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.
Auch gibt es bei einer XAMPP-Installation
Grund: Wer macht denn SOWAS?
Tach!
Auch gibt es bei einer XAMPP-Installation
- Kein Windows + XAMPP benutzen.
Was konkret ändert das in Bezug auf den Fehler, das nicht auch unter Windows entsprechend konfiguriert werden kann?
dedlfix.
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...)
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.
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.
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.
(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...
(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
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.