PHP feof() true zurück, bevor das Ende der Datei
Hatte ich ein seltsames PHP problem die letzten Tage, wo die feof () - Funktion true zurück, bevor die Datei zu Ende. Unten ist ein Skelett von meinem code:
$this->fh = fopen("bigfile.txt", "r");
while(!feof($this->fh))
{
$dataString = fgets($this->fh);
if($dataString === false && !feof($this->fh))
{
echo "Error reading file besides EOF";
}
elseif($dataString === false && feof($this->fh))
{
echo "We are at the end of the file.\n";
//check status of the stream
$meta = stream_get_meta_data($this->fh);
var_dump($meta);
}
else
{
//else all is good, process line read in
}
}
Durch viele Tests habe ich festgestellt, dass das Programm funktioniert gut auf alles, ausser einer Datei:
- Die Datei auf dem lokalen Laufwerk gespeichert.
- Diese Datei ist rund 8 Millionen Zeilen lang durchschnittlich irgendwo um 200-500 Zeichen pro Zeile.
- Es wurde bereits gereinigt und unter näherer Betrachtung mit einem hex-editor, keine abnormalen Zeichen gefunden wurden.
- Das Programm wiederholt nicht auf Linie 7172714, wenn es glaubt, es hat erreicht das Ende der Datei (obwohl es noch ~800K Zeilen Links).
- Die ich getestet habe, das Programm auf Dateien, die hatten weniger Zeichen pro Zeile wurden aber zwischen 20-30 Millionen Zeilen ohne Probleme.
- Ich habe versucht mit dem code aus einem Kommentar auf http://php.net/manual/en/function.fgets.php nur um zu sehen, ob es etwas in meinem code das Problem verursacht und die 3rd-party-code nicht auf der gleichen Linie. EDIT: erwähnenswert ist auch, dass die 3rd-party-code verwendet, fread() statt fgets().
- Ich habe versucht, die Angabe von mehreren Puffer in der fgets-Funktion und keine von Ihnen Unterschied.
Die Ausgabe von var_dump($meta) ist wie folgt:
array(9) {
["wrapper_type"]=>
string(9) "plainfile"
["stream_type"]=>
string(5) "STDIO"
["mode"]=>
string(1) "r"
["unread_bytes"]=>
int(0)
["seekable"]=>
bool(true)
["uri"]=>
string(65) "full path of file being read"
["timed_out"]=>
bool(false)
["blocked"]=>
bool(true)
["eof"]=>
bool(true)
}
Bei dem Versuch, herauszufinden, was die Ursache feof true zurück, bevor das Ende der Datei, ich denke mal, dass entweder:
A) Etwas verursacht die fopen-stream zu Versagen und dann nichts ist in der Lage zu Lesen (was feof true zurück)
B) Es gibt einige Puffer irgendwo, das füllen und Verwüstung
C) Die PHP-Götter sind wütend
Habe ich gesucht weit und breit zu sehen, ob jemand hatte dieses Problem und finde keine Instanzen außer in C++, wenn die Datei gelesen wird, in der via text-Modus anstelle von Binär-Modus, und wurde das Problem verursacht.
UPDATE:
Ich hatte mein Skript ständig die Ausgabe der Anzahl der Zeiten, die die lese-Funktion iteriert und die eindeutige ID des Benutzer, verbunden mit dem Eintrag den es gefunden, neben ihm. Das Skript ist immer noch nicht nach Strich 7172713 aus 7175502, aber die unique-ID des letzten Benutzers in der Datei wird zeigen, bis auf 7172713. Es scheint, dass das problem ist für einige Grund Linien werden übersprungen und nicht gelesen werden. Alle Zeilenumbrüche vorhanden sind.
- Ist es möglich, dass php genügend Speicher Lesen der Datei?
- Vergaß zu erwähnen, dass die read-Funktion aufgerufen, für die Blöcke von Zeilen. Es liest 500 Zeilen, einige Verarbeitung und gibt einen Wert zurück und speichert die Letzte Position in einer Klasse-weite variabel. Das nächste mal, wenn es aufgerufen wird, liest es die nächsten 500 Zeilen ab, wo es aufgehört mit dem class-Breite variabel. Alles ist richtig befasst mit unset und während der überwachung der server-Speichernutzung ist mir noch nicht aufgefallen, alles normal. Denn das war zu kompliziert, zu testen, zu halten, schrieb ich diesen code einfach mit unset die Zeile gelesen, in der auf einer erfolgreichen Linie Lesen. Noch sehen das gleiche problem.
- haben Sie versucht, mit
rb
= Read Binary statt nurr
? - Wusste nicht, dass Sie tun könnte, dass in PHP, da es nicht auf der Liste der Optionen in der fopen-docs. Ich werde es jetzt versuchen und lassen Sie wissen, wenn das funktioniert!
- ja, für einige Grund, es ist nicht wirklich dokumentiert, aber es ist gültig und wird verwendet in einigen der php.net Beispiele
- Sah nur diese Beispiele. Ich habe auch gerade angefangen den test und es wird angezeigt, dass PHP lassen Sie mich diese option verwenden. Ich weiß, in ein paar Minuten ob es funktioniert hat, nachdem das script fertig ausgeführt wird.
- Kein Glück, es nur versäumt, in der gleichen Zeile. Aber danke für die binary-lese-Tipp, ich werde weiterhin verwenden Sie es, wie es ist viel besser üben.
- Das ist schade, was ich sonst nicht kenne. Jemand geschrieben code auf meiner website für das herunterladen von großen Dateien, ich habe es nicht gelesen, aber auf der Linie
72
es sieht aus wie es könnte einige code, der könnte Ihnen helfen. phpsnips.com/snip-579#.VLYBwc3d9hE - Danke, ich werde schauen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
müssen Sie teilen Sie Ihre Datei, oder erhöhen Sie den timeout in php
von:
max_execution_time = 60
; auch höher, wenn Sie müssen
weil:
Gibt TRUE zurück, wenn der Dateizeiger auf EOF oder ein Fehler Auftritt (einschließlich der socket-timeout); andernfalls gibt Sie FALSE zurück.
siehe:http://php.net/manual/en/function.feof.php
fgets() ist scheinbar zufällig Lesen in einigen Zeilen, in denen Inhalte wie leer. Das Skript eigentlich macht es an das Ende der Datei, obwohl meine Tests zeigten, dass die Zeilennummern Lesen war hinter durch die Art und Weise habe ich den Fehler überprüfen (und die Art und Weise der Fehlerprüfung geschrieben wurde, in der 3rd-party code). Jetzt die eigentliche Frage ist, was die Ursache fgets() und fread() der Meinung, dass eine Zeile leer ist, obwohl man es nicht ist. Ich werde darum bitten, dass als eine separate Frage, dass eine änderung in Thema. Danke Euch allen für Eure Hilfe!!!
Ebenfalls, nur damit niemand hängen gelassen, der Grund, warum die 3rd-party-code nicht funktionieren wird, weil es beruhte auf einer Zeile mindestens mit einem Zeilenumbruch, wo das aktuelle problem mit fgets und fread Rückgabe ein leerer string nicht geben, das Skript, was es braucht, um zu wissen, die Linie, die jemals existierte, so ist es weiterhin versuchen zu ausführen über das Ende der Datei. Unten ist die leicht modifizierte 3rd-party-Skript, welches ich immer noch als hervorragende Grundlage, es ist die Ausführungsgeschwindigkeit.
Das original-Skript gefunden werden kann in den Kommentaren hier: http://php.net/manual/en/function.fgets.php und ich nehme absolut keine Kredit für Sie.
UPDATE: Nach Stunden der Suche, Analyse, Haare ziehen, etc. es scheint, dass der Täter war eine nicht abgefangene schlechten Charakter - in diesem Fall ein 1/2 Zeichen hex-Wert BD. Beim generieren der Datei, die ich war Lesung aus dem Skript verwendet stream_get_line() für das Einlesen der Zeile aus der ursprünglichen Quelle. War es dann entfernen soll alle schlechten Charaktere (es scheint, dass meine regex war nicht bis zu par) und dann mit str_getcsv() konvertieren den Inhalt in ein array tun, einige Bearbeitung, dann schreiben Sie eine neue Datei (die, die ich versucht hatte, Sie zu Lesen). Irgendwo in diesem Prozess, wahrscheinlich str_getcsv(), die 1/2 Charakter verursacht die ganze Sache nur legen Sie eine leere Zeile anstelle der Daten. Mehrere tausend platziert wurden diese alle in der Datei (wo auch immer das 1/2-symbol erscheint). Diese aus der Datei werden auf die richtige Länge, aber für die EOF erreicht werden zu schnell beim zählen der input basiert auf eine bekannte Anzahl von Zeilen. Ich möchte allen danken, die mir geholfen haben, mit diesem problem, und ich bin sehr traurig, dass die wahre Ursache nichts zu tun hatte mit meiner Frage. Aber wenn es nicht gewesen für alle Anregungen und Fragen würde ich nicht geschaut haben, an den richtigen stellen.
Lektion aus dieser Erfahrung gelernt haben - wenn EOF erreicht ist, ist auch schnell der beste Ort, um suchen ist für Instanzen von double line breaks. Wenn ein Skript schreiben, dass liest aus der formatierten Datei eine gute Praxis ist, zu überprüfen, ob diese. Unten ist mein original code geändert um genau das zu tun: