Performance, nur erste zeile lesen: fope file, file_get_contens
Mike
- php
Hallo,
ich habe einiges an Dateien, deren Inhalt ich auslesen möchte zur Weiterverarbeitung. Es ist aber lediglich die erste Zeile interessant.
Wenn ich nun die bekannten Wrapper file, file_get_contents, include, usw... nutze ziehe ich ja erst einmal das ganze File rein. Und wenn ich nur ein paar Bytes brauche megabitgrosse Inhalte zu lesen finde ich unschön.
Jetzt dachte ich vielleicht den klassischen Weg mit fread, aber wie sieht das in der Performance aus, was wäre der speicherschonenste Weg, nur die erste Zeile auszulesen?
Mike
Lieber Mike,
Jetzt dachte ich vielleicht den klassischen Weg mit fread, aber wie sieht das in der Performance aus, was wäre der speicherschonenste Weg, nur die erste Zeile auszulesen?
ja.
Liebe Grüße,
Felix Riesterer.
Mahlzeit Felix Riesterer,
wie sieht das in der Performance aus, was wäre der speicherschonenste Weg, nur die erste Zeile auszulesen?
ja.
War das jetzt der fingerschonendste Weg zu antworten? ;-)
MfG,
EKKi
Lieber EKKi,
wie sieht das in der Performance aus, was wäre der speicherschonenste Weg, nur die erste Zeile auszulesen?
ja.
War das jetzt der fingerschonendste Weg zu antworten? ;-)
ja.
Liebe Grüße,
Felix Riesterer.
Hi,
Jetzt dachte ich vielleicht den klassischen Weg mit fread, aber wie sieht das in der Performance aus, was wäre der speicherschonenste Weg, nur die erste Zeile auszulesen?
ja.
ich gehe mal davon aus, du meinst also fread.
Ich habe das nun probiert mit 1000 Dateien ca. 500kb/Datei:
$handle = fopen($fl, "r");
$cont = fread($handle,100);
$cont = substr($cont,0,strpos($cont,"\r\n"));
fclose($handle);
Aber im Vergleich zu:
$cont= file($fl);
$cont= $cont[0];
war das nicht wirklich viel schneller.
Wie funktioniert das rein technisch? Soweit ich das sehe, muss auch bei fread erst mal das ganze File reingezogen werden, also nicht wie ich erhofft hatte, das der Verbindungsaufbau abbricht sobald Length erreicht wird, oder ist das doch so?
Mike
Lieber Mike,
ich gehe mal davon aus, du meinst also fread.
egal, ob fread oder fgets. Im Prinzip erfüllen beide Funktionen für Dein Anliegen denselben Zweck.
Ich habe das nun probiert mit 1000 Dateien ca. 500kb/Datei:
Wenn die Dateien in den Megabyte-Bereich gehen (so meine ich Deinen OP gelesen zu haben), dann macht sich das bald an der Speichergrenze bemerkbar, insbesondere, wenn Du 8MB Arbeitsspeicher in PHP zur Verfügung hast, eine Datei aber mal eben auch so an diese Grenze stößt.
$handle = fopen($fl, "r");
$cont = fread($handle,100);
$cont = substr($cont,0,strpos($cont,"\r\n"));
fclose($handle);
Bist Du sicher, dass die erste Zeile genau 98 Zeichen enthält? Wenn nicht, warum dann nicht so?
$d = fopen($fl, 'rb');
$cont = '';
while (!strpos($cont, "\n")) {
$cont .= fread($d, 20);
}
$cont = preg_replace('~^([^\r\n]+).*~', '\\1', $cont);
fclose($d);
Liebe Grüße,
Felix Riesterer.
Hi Felix,
Bist Du sicher, dass die erste Zeile genau 98 Zeichen enthält? Wenn nicht, warum dann nicht so?
Es sind weniger daher max grenze.
$d = fopen($fl, 'rb');
$cont = '';
while (!strpos($cont, "\n")) {
$cont .= fread($d, 20);
}
$cont = preg_replace('~^([^\r\n]+).*~', '\1', $cont);
fclose($d);
>
ich habe das mal probiert aber dann kommen schon Inhalte der 2.zeile mit rein. Und ist es nicht sogar so, dass gerade regex nicht zu empfehlen sind bei solchen Aufgaben, eben wegen Performance?
Danke
Mike
Lieber Mike,
$cont = preg_replace('~^([^\r\n]+).*~', '\1', $cont);
ich habe das mal probiert aber dann kommen schon Inhalte der 2.zeile mit rein.
ja, in meinem Muster fehlt ein (?s), damit nicht zeilen-orientiert gelesen wird.
$cont = preg_replace('~(?s)^([^\r\n]+).*~', '\\1', $cont);
Und ist es nicht sogar so, dass gerade regex nicht zu empfehlen sind bei solchen Aufgaben, eben wegen Performance?
Diese RegEx-Geschichte wird einmal pro Datei für eine überschaubare Stringlänge ausgeführt. Das ist OK. Hätte ich eine RegEx-Prüfung in der Schleife vorgenommen, wäre das etwas anderes gewesen - dort verwende ich aber strpos().
Ich habe mich deswegen für eine RegEx-Prüfung entschieden, da ich gerne auf "Nummer sicher" gehe, und in Deinen Dateien vielleicht einmal ein Zeilenende ohne Linefeed (\r) stehen könnte. Deine strpos()-Funktion würde dieses dann nicht finden...
Liebe Grüße,
Felix Riesterer.
echo $begrüßung;
Jetzt dachte ich vielleicht den klassischen Weg mit fread, aber wie sieht das in der Performance aus, was wäre der speicherschonenste Weg, nur die erste Zeile auszulesen?
Es gibt zum zeilenweisen Lesen die Funktion fgets().
Ich habe das nun probiert mit 1000 Dateien ca. 500kb/Datei:
$handle = fopen($fl, "r");
$cont = fread($handle,100);
$cont = substr($cont,0,strpos($cont,"\r\n"));
fclose($handle);Aber im Vergleich zu:
$cont= file($fl);
$cont= $cont[0];war das nicht wirklich viel schneller.
Und es wird noch (geringfügig) langsamer, wenn du den notwendigen Code zur Fehlerbehandlung einbaust. PHP-Funktionsaufrufe benötigen auch Rechenzeit. Wenn etwas intern gemacht werden kann, beispielsweise das Öffnen und Lesen innerhalb von file(), dann kann es durchaus sein, dass das komplette Lesen schneller ist als das verkürzte plus PHP-Funktionsaufrufe.
Wie funktioniert das rein technisch? Soweit ich das sehe, muss auch bei fread erst mal das ganze File reingezogen werden, also nicht wie ich erhofft hatte, das der Verbindungsaufbau abbricht sobald Length erreicht wird, oder ist das doch so?
Das steht doch unzweifelhaft im PHP-Handbuch: fread()
echo "$verabschiedung $name";
你好 dedlfix,
Und es wird noch (geringfügig) langsamer, wenn du den notwendigen Code zur Fehlerbehandlung einbaust. PHP-Funktionsaufrufe benötigen auch Rechenzeit. Wenn etwas intern gemacht werden kann, beispielsweise das Öffnen und Lesen innerhalb von file(), dann kann es durchaus sein, dass das komplette Lesen schneller ist als das verkürzte plus PHP-Funktionsaufrufe.
Der Vorteil einer Lösung mit fgets() ist, dass sie besser skaliert. Wenn die Datei 100MB groß ist, kann die Verteilung der Rechenzeit schon anders aussehen bei file(). Bei fgets() dagegen ist der Aufwand (mehr oder weniger) identisch zu einer 10-Byte-Datei.
再见,
克里斯蒂安
(Hallo|Hi(ho)|Tag|Mahlzeit) Mike,
ich habe einiges an Dateien, deren Inhalt ich auslesen möchte zur Weiterverarbeitung. Es ist aber lediglich die erste Zeile interessant.
Wenn ich nun die bekannten Wrapper file, file_get_contents, include, usw... nutze ziehe ich ja erst einmal das ganze File rein. Und wenn ich nur ein paar Bytes brauche megabitgrosse Inhalte zu lesen finde ich unschön.
file_get_contents() kennt seit einiger Zeit die Parameter offset und maxlen, mit denen man die Anzahl der eingelesen Bytes auf einen bestimmten Bereich eingrenzen kann. Gegenüber fopen(), fread() und fclose() spart file_get_contents() nicht nur Tipparbeit sondern auch ein paar Fehlerprüfungen.
Jetzt dachte ich vielleicht den klassischen Weg mit fread, aber wie sieht das in der Performance aus, was wäre der speicherschonenste Weg, nur die erste Zeile auszulesen?
Um Zeilen (mit PHP) auszulesen, benutze ich in der Regel fgets().
MffG
EisFuX