Datei in Variable speichern

F

Friedrich

Guest
Hallo,

mittels $text = file_get_contents('gedcom.txt'); kann man ja eine ganze Datei in eine Variable speichern. Gut so. Nur was ist, wenn die Text-Datei 2 MByte oder sogar 10 MByte gross ist?

Und ist es "normal", dass manchmal (oder auch ziemlich oft) bei einem 600 KByte großen File, wo er jede Zeile nach und nach durchgeht mittels for-Schleife, manchmal einfach 5 Minuten oder so bei einer Zeile verweilt? Woran könnte das liegen? Nach jedem Zeilendurchlauf wird per echo-Befehl etwas ausgegeben, könnte das was damit zu tun haben, dass immer erst wieder was an den Browser übertragen werden muss und dass das irgendwas überlastet?

Es gibt ja noch die Variante immer nur eine Zeile einer Datei einzulesen. Wäre dies nicht besser bei 5 MByte großen Dateien? Und würde es dann nicht schneller gehen?

Friedrich
 
Hallo.

QUOTE (Friedrich @ Fr 23.9.2005, 18:10)[...]
Und ist es "normal", dass manchmal (oder auch ziemlich oft) bei einem 600 KByte großen File, wo er jede Zeile nach und nach durchgeht mittels for-Schleife, manchmal einfach 5 Minuten oder so bei einer Zeile verweilt? Woran könnte das liegen? Nach jedem Zeilendurchlauf wird per echo-Befehl etwas ausgegeben, könnte das was damit zu tun haben, dass immer erst wieder was an den Browser übertragen werden muss und dass das irgendwas überlastet?
[...]

Als normal würde ich dieses verhalten nicht empfinden, vermutlich könnte dabei irgendein Zeichen Probleme bereiten, je nachdem, wie Du diese Datei Zeilenweise ausliest. Auch wird normalerweise erst nach Ablauf des PHP-Scriptes die Ausgabe an den Browser übermittelt, es sei denn, die Standardkonfiguration der php.ini wurde geändert oder Du verwendest die Funktion flush() um eine vorzeitige Ausgabe zu erzwingen.

Eigentlich sollte PHP auch keine großen Schwierigkeiten damit haben Dateien von 10 MB auszulesen und abzuarbeiten.




QUOTE [...]
Es gibt ja noch die Variante immer nur eine Zeile einer Datei einzulesen. Wäre dies nicht besser bei 5 MByte großen Dateien? Und würde es dann nicht schneller gehen?
[...]

Ja, es gibt Varianten um eine Datei stückchenweise einzulesen, doch denke ich nicht, dass diese umbedingt schneller sein werden, als wenn man die Datei gleich komplett einliest, dies hängt aber natürlich auch von den Verwendungszweck ab (z.B. wenn das Script nicht unbedingt die ganze Datei einlesen braucht).


Ich denke file_get_contents() bzw. ein fopen() in verbindung mit einen fread(), welches die Datei dann gleich ganz ausliest, sind wohl die besten Methoden um eine Datei schnell komplett auszulesen (ansonsten einfach mal eine Preformence-Kontrolle machen bei den unterschiedlichen Methoden).


Um genauere Aussagen machen zu können, müsste ich aber schon den Code sehen können.



MfG Sascha Ahlers
 
Hallo,

>> Auch wird normalerweise erst nach Ablauf des PHP-Scriptes die Ausgabe an den Browser übermittelt, es sei denn, die Standardkonfiguration der php.ini wurde geändert oder Du verwendest die Funktion flush() um eine vorzeitige Ausgabe zu erzwingen.

Mitten in der For-Schleife gibt er einfach per echo-Befehl etwas aus. Und deshalb muss ja immer wieder etwas an den Browser übergeben werden.

Gerade funktioniert es wieder richtig gut. Liegt es dann vielleicht an den Server? Denn dort geht er ja immer das Skript durch.

Friedrich


 
QUOTE (Friedrich @ Fr 23.9.2005, 18:33)[...]
Gerade funktioniert es wieder richtig gut. Liegt es dann vielleicht an den Server? Denn dort geht er ja immer das Skript durch.
[...]

Es kann natürlich am Server liegen, doch kann dies genauso entsprechend durch das Script mit beeinflusst werden.
Um dies sicher sagen zu können, müsste ich mehr Einzelheiten kennen, aber es wäre durchaus denkbar. Der letzte Provider bei dem ich (noch) Webspace habe, hat z. B. riesige Probleme mit der MySQL Datenbank was entweder am Server liegt oder einfach an der Last, die dort drauf ist. Wogegen der Provider natürlich nichts macht, trotz mehrerer Hinweise.



MfG Sascha Ahlers

PS: Der Provider wird ab nächsten Monat deswegen auch Geschichte sein (zumind. bei mir)
 
Hallo!

nach meiner Meinung liegt es gar nicht an der Programmierung, da es mal da mal da abbricht.

Hier eine Testdatei: http://www.adamio.com/test.txt

Meine Idee: Da die Datei richtig lang ist braucht das Skript auch einige viele Minuten. Könnte es dann sein, dass der Anbieter nach soundsovielen Minuten ein Skript, was die ganze Zeit durchlaufen wird, einfach abbricht, weil es ja auch ein fehlerhaftes Skript sein könnte, was dann ewig laufen würde in einer Schleife? Wenn dem so sein sollte, was kann ich tun, damit der Server weiß, dass noch alles in Ordnung ist? Hilft es denn, eine Sekunde Pause immer zu machen (gibt es ja einen PHP-Befehl), oder interessiert das den Server nicht?

Friedrich
 
Normalerweise bricht der Server die Ausführung eines Scriptes nach 30 Sekunden einfach ab, es sein denn, der Wert "max_execution_time" wurde verändert (ob innerhalb der php.ini, per Webserver Konfiguration oder im Script selber), doch selbst dann sollte das Script nach einer gewissen Zeit abbrechen, solange der Wert nicht auf "0" gesetzt wurde.

Eine Pause wird den Server kaum interessieren, die Verzögerung ist eigentlich nur für gewisse Sonderfälle vorgesehen, welche meistens außerhalb der Web-Programmierung. Ich glaube auch nicht, dass diese Pause bei deinen Problem einen Sinn ergibt.


Klar, braucht das Script etwas länger wenn die Datei länger ist, besonders wenn das Script innerhalb einer Schleife arbeitet. Und natürlich kommt es auf die Befehlsanzahl innerhalb der Schleife an. Aber letzendlich sollen ja auch Datenbanken diese Zugriffzeiten minimieren. Vielleicht wäre ja eine Berkeley DB [1] sinnvoller als eine reine Textdatei. ;-)
Oder gleich auf MySQL oder PostgreSQL zurückgreifen.
Doch gehe ich ja auch an große Dateien ran und habe diese Probleme bisher nie gehabt.



MfG Sascha Ahlers

[1] PHP.net: Berkeley DB
 
Hallo!

Die erste Idee kann es nicht sein: "Legt die Zeit in Sekunden fest, die ein Script laufen darf. Ist diese Zeit abgelaufen, wird ein Fehler zurückgegeben." Denn am Ende wird kein Fehler ausgegeben, sondern es wird einfach nichts mehr gemacht.
Fest steht, dass es nicht an einer bestimmten Stelle abbricht, also liegt es nicht mit den Daten zusammen, die übertragen werden sollen.

Friedrich
 
QUOTE (Friedrich @ Sa 24.9.2005, 13:28)[...] Die erste Idee kann es nicht sein: "Legt die Zeit in Sekunden fest, die ein Script laufen darf. Ist diese Zeit abgelaufen, wird ein Fehler zurückgegeben."
Denn am Ende wird kein Fehler ausgegeben, sondern es wird einfach nichts mehr gemacht. [...]

Ja, ein Fehler wird zurückgegen, es heißt aber noch lange nicht, dass dieser direkt ausgegeben wird. Nebenbei war dies nur eine Erklärung, keine Idee. ;-)



MfG Sascha Ahlers
 
wie wäre es mit einer leicht anderen richtung...
mach aus dieser Datei wenn möglich doch eine .php
und schreib an den Anfang einfach <? echo'
und ans ende ' ?>
uund lade dies dann mit include oder mit CODE ob_start();
include("datei.php");
$inhalt= ob_get_contents();
ob_end_clean();
 
PHP hat auch ein Speicherlimit. Man bedenke dies.

Wäre aber wirklich vorteilhaft, wenn man ein Stück von dem "Code" sehen könnte. Insbesondere die Schleife. Da kann man gerade in PHP sehr schnell ein sehr langsames Skript produzieren
wink.gif
 
QUOTE (Metaman @ Sa 24.9.2005, 22:12)wie wäre es mit einer leicht anderen richtung...
mach aus dieser Datei wenn möglich doch eine .php
und schreib an den Anfang einfach <? echo'
und ans ende ' ?>
uund lade dies dann mit include oder mit [...]

Die kurzen PHP-Tags würde ich nach Möglichkeit versuchen zu meiden.
Desweiteren was möchtest Du mit diesem eher unsinnigen Code erreichen?
- In dem Bezug gibt es bessere Methoden, die auch binär-sicher sind (z.B. file_get_contents, file oder fread).


@Friedrich:
Na ja, wie bull treffend sagt, ohne den Code kann Dir nur schwer weitergeholfen werden. Nur als Anmerkung nochmal kurz, wenn nach Ablauf der maximalen Ausführzeit keine Warnmeldung kommt, wird Sie auch nicht bei überschreiten des Speicherlimit erscheinen.



MfG Sascha Ahlers
 
Hallo,

ich habe versucht, den Code auf das Wichtigste zu kürzen:

CODE $text=file_get_contents("$datei");
$text=str_replace("\r","\n",$text);

$zeilenanzahl=substr_count($text,"\n");
$textneu=explode("\n", $text);

for($i=0; $i<=$zeilenanzahl;$i++)
{
$neuereintrag="";
$textzeile=$textneu[$i];
$textzeile=trim($textzeile);

if($textzeile[0]=="0")
{
if(strpos($textzeile,"@")<>0 and strpos($textzeile,"INDI")>0){$eintrag="person";}
if(strpos($textzeile,"@")<>0 and strpos($textzeile,"FAM")>0){$eintrag="familie";}
if(strpos($textzeile,"@")==0 and strpos($textzeile,"TRLR")>0){echo "<div class=\"abfolge\">Übertragung erfolgreich abgeschlossen.<p>Solange Sie Verknüpfungen nicht ändern, können alle gerade eingefügten Vorfahren wieder gelöscht werden. <a href=\"/$n1/login/sbearbeiten.html\" target=\"_top\">Aktualisieren</a></div>";die;}

while($neuereintrag<>"ja")
{
$zahl=$zahl+1;
$textzeile=$textneu[$zahl];
$textzeile=trim($textzeile);
$teiletext=explode(" ",$textzeile);

if($teiletext[0]=="0")
{
$textzeile=explode("@", $textzeile);
$neuepersontext="$textzeile[1]";

if($eintrag=="person")
{
$datum=$datum+1;
$text=ereg_replace("$textzeile[1]", "$datum", $text);
$textneu=explode("\n", $text);
}
}
else
{
if($eintrag=="person")
{
$felder1=" NAME SOUR RELI SEX NOTE DATE OCCU BIRT CHR DEAT BURI";
$felder2=" DATE PLAC";

if($teiletext[0]=="1")
{
if($teiletext[1]=="NAME")
{
$name=substr($textzeile,6);
$name=explode("/", $name);

$name[0]=trim($name[0]);
$name[1]=trim($name[1]);
$name[2]=trim($name[2]);

if(empty($name[2]))
{
$vorname=$name[0]; $nachname=$name[1];
}
else
{
$vorname=$name[2]; $nachname=$name[1];
}
}

if($teiletext[1]=="SOUR"){$quellen=substr($textzeile,6);}
if($teiletext[1]=="RELI"){$religion=substr($textzeile,6);}

if(strpos($felder1,$teiletext[1])>0)
{
$kategorie=$teiletext[1];
}
else
{
$gedcominfo="$gedcominfo\n$textzeile";
}
}

if($teiletext[0]=="2")
{
if($kategorie=="NOTE" and $teiletext[1]=="CONT"){$weitereinfo=substr($textzeile,6); $informationen="$informationen $weitereinfo";}
if($kategorie=="BIRT" and $teiletext[1]=="DATE"){$geburtsdatum=substr($textzeile,6);}

if(strpos($felder2,$teiletext[1])==0)
{
$gedcominfo="$gedcominfo\n1 $kategorie\n$textzeile";
}
}
}

if($eintrag=="familie")
{
$felder1=" HUSB WIFE CHIL MARR";
$felder2=" DATE PLAC";

if($teiletext[0]=="1")
{
if($teiletext[1]=="HUSB"){$ehemann=explode("@", $textzeile); $ehemann="$ehemann[1]";}
if($teiletext[1]=="WIFE"){$ehefrau=explode("@", $textzeile); $ehefrau="$ehefrau[1]";}
if($teiletext[1]=="CHIL"){$kind=explode("@", $textzeile); $kinder="$kinder\{$kind[1]}";}

if($teiletext[1]=="MARR"){$heirat=substr($textzeile,6);}

if(strpos($felder1,$teiletext[1])>0)
{
$kategorie=$teiletext[1];
}
else
{
$gedcominfo="$gedcominfo<br>$textzeile";
}
}

if($teiletext[0]=="2")
{
if($kategorie=="MARR" and $teiletext[1]=="DATE"){$heiratsdatum=substr($textzeile,6);}
if($kategorie=="MARR" and $teiletext[1]=="PLAC"){$heiratsort=substr($textzeile,6);}

if(strpos($felder2,$teiletext[1])==0)
{
$gedcominfo="$gedcominfo\n1 $kategorie\n$textzeile";
}
}
}
}

$textzeileneu=$textneu[$zahl+1];
if($textzeileneu[0]=="0")
{
$neuereintrag="ja";
}
}

if($eintrag=="person")
{
############################
### Neue Person einfügen ###
############################
}

if($eintrag=="familie")
{
##############################
### Verknüpfungen einfügen ###
##############################
}
}
}


Übrigens besitzt die einzufügende Datei beinahe 15000 Zeilen.
Es geht um das Einfügen von einer GEDCOM-Datei (für Ahnenforschung). Pro Zeile steht eine Informationen. Fängt eine Zeile mit 0 an wird zum Beispiel ein neuer Vorfahre angefangen, 1 und 2 etc. beziehen sich dann darauf.
Die Schleife geht meiner Meinung nach nicht kleiner.

Was mir jetzt aber noch als Idee aufgekommen ist (über Nacht): Er soll einfach nur die ersten 1000 Zeilen abarbeiten und dann lädt er per Location-Befehl die gleiche Datei, allerdings fängt er jetzt bei Zeile 1000 an zu arbeiten. Damit würde das Abarbeiten sozusagen kurz unterbrochen werden und der Server dürfte es nicht als Endlosschleife interpretieren. Oder?

Friedrich
 
Das sind schon mehr Informationen, ich schaue mir nachher mal den Code etwas genauer an, doch hört sich das für mich so an, dass Du wohl doch besser eine richtige Datenbank verwenden solltest.
Also auch mal so aus interesse, was sind den die Gründe dafür, dass Du die Werte in eine Textdatei speicherst als gleich in eine Datenbank (andere Programme, keine Datenbank, nicht die entsprechenden PHP Module, etc.)?



MfG Sascha Ahlers
 
QUOTE 1 SOUR FTW
2 VERS 4.00
2 NAME Family Tree Maker for Windows
2 CORP Broderbund Software, Banner Blue Division
3 ADDR 39500 Stevenson Pl. #204
4 CONT Fremont, CA 95439
3 PHON (510) 794-6850
1 DEST PAF
1 DATE 16 Oct 1997
1 CHAR IBMPC
1 SUBM @SUBM@
1 FILE C:\myfiles\Jay Webb.GED

Ich sehe schon, warum Du Dir diese Mühe machst, wäre es aber nicht trotzdem Sinnvoll diese Daten in eine Datenbank zu speichern. Via Script einmal komplett einlesen bzw. auch wieder in eine Datei speichern? - Zumindestens bei so großen Datenmengen.



MfG Sascha Ahlers
 
Hallo,

nun, die Textdatei wird ja sousagen übergeben per Upload-Formular. Du meinst, dass ich danach den ganzen Inhalt in der Datenbank sofort speichern sollte, oder die Informationen in einer Textdatei auf dem Server hinterlegen sollte?
Aber das Ding dann ist ja wieder: Ich möchte all die Informationen in meine eigene Datenbank eingefügt sehen, dass heißt, dass ich jede Zeile auslesen muss und nachsehe, in welches Feld ich die Information speichern soll.

Würde es denn Vorteile bringen, erst eine Textdatei auf dem Server zu erstellen, als sofort alles in einem String zu speichern und abzuarbeiten? Meiner Meinung nach wäre das am Ende das Gleiche, oder?

Was hällst du von der Idee, dass man die ersten 100 Zeilen abarbeitet, er sich merkt, wo er gerade ist und dann per Location die Datei wieder aufruft?

Friedrich
 
QUOTE (Friedrich @ So 25.9.2005, 19:22)[...]
Würde es denn Vorteile bringen, erst eine Textdatei auf dem Server zu erstellen, als sofort alles in einem String zu speichern und abzuarbeiten? Meiner Meinung nach wäre das am Ende das Gleiche, oder?
[...]

Da müsstest Du mir mal erklären, was Du genau vor hast. Ich weiß nun, dass Du die Datei abarbeiten musst, welche Du über einen Upload bekommst und diese für ein Programm ist, welches wohl von Microsoft ist.
Nebenbei war das nur ein Vorschlag von mir, denn 15 MB große Dateien müssen ja auch von irgendwo her kommen.




QUOTE [...]Was hällst du von der Idee, dass man die ersten 100 Zeilen abarbeitet, er sich merkt, wo er gerade ist und dann per Location die Datei wieder aufruft?
[...]

Das wäre eine Möglichkeit, würde ich aber versuchen zu vermeiden, auch ist mir selber nur eine Anwendung bekannt, die so arbeitet und diese ist eher für Webdesigner gedacht und nicht für den 08/15 Benutzer.



MfG Sascha Ahlers
 
Hallo,

ich programmiere die Seite Adamio.com. Für Familienforscher gibt es das Format GEDCOM, das von vielen Programmen unterstützt wird. Damit kann man die Vorfahrendaten von Programm zu Programm übertragen.

Auf Adamio.com soll dies auch funktionieren. Familienforscher sollen ihre bereits erforschten Vorfahren eintragen können. Das geht über ein Upload-Formular (wo sie eine Gedcom-Datei auswählen, die mit einem anderen Ahnenforschungsprogramm erstellt wurde).
All die Daten in der Datei möchte ich nun in meiner Adamio.com-Datenbank speichern, damit später andere Forscher nach gleichen Vorfahren suchen können.

QUOTE Das wäre eine Möglichkeit, würde ich aber versuchen zu vermeiden, auch ist mir selber nur eine Anwendung bekannt, die so arbeitet und diese ist eher für Webdesigner gedacht und nicht für den 08/15 Benutzer.


Bei dieser Idee müsste ich zuerst eine Textdatei mit all den Daten auf dem Server erstellen. Würde in der Programmierung vielleicht etwas komplizierter sein. Was würde dagegen sprechen?

Friedrich
 
Meß mal wie lange der "Code" (traue mich kaum, es so zu bezeichnen) braucht.

CODE function getmicrotime()
{
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}

$zeit = getmicrotime();


<Zu messender Abschnitt>


CODE echo "<p>Zeit: ",getmicrotime() - $zeit, " Sekunden";


Bevorzugt zu messender Abschnitt:

CODE $text=file_get_contents("$datei");
$text=str_replace("\r","\n",$text);

$zeilenanzahl=substr_count($text,"\n");
$textneu=explode("\n", $text);


und sag uns was rauskommt. Einen mehrere Hundert kB langen String in ein Array mit mehreren tausend Elementen umzuwandeln verbraucht Speicher und ist langsam. Für das, was hier benötigt wird, könnte strtok auch eine (schnellere) Alternative sein.
 
Hallo,

das Uploaden dauert nicht allzu lange bei einer 200 KByte Text-Datei, selbst mit einer 1 MByte Datei funktioniert es bestens. Das aufsplitten dauert auch nicht lange, was lange dauert ist natürlich die For-Schleife, wo jede Zeile ausgelesen wird. Nur denke ich, dass das normal ist.

Interessant, was ich jetzt herausgefunden habe: Das Abarbeiten einer riesigen Datei hat rund 2 Minuten gedauert, was ja eingentlich nicht gehen dürfte, wenn der Abbruch bereits nach 30 Sekunden Ausführungszeit gestartet wird.

Friedrich
 
Zurück
Oben