2010-11-19 16 views
4

Ich schrieb ein Programm zum Generieren großer .SQL-Dateien zum schnellen Auffüllen sehr großer Datenbanken. Ich habe es in PHP geschrieben. Als ich mit der Codierung begann, benutzte ich fopen() und fwrite(). Wenn Dateien zu groß wurden, würde das Programm die Kontrolle an die Shell zurückgeben und die Datei wäre unvollständig.Ist fopen() vom Dateisystem begrenzt?

Leider bin ich mir nicht sicher, wie groß 'zu groß' ist. Ich denke, es könnte um 4GB gewesen sein.

Um dieses Problem zu lösen, hatte ich die Datei echo zu stdout. Ich leitete es um, als ich das Programm wie folgt anrief:

[[email protected]]$ php generatesql.php > myfile.sql 

Welche funktionierte wie ein Charme. Meine Ausgabedatei endete ungefähr 10 GB.

Meine Frage ist also: Sind fopen() und fwrite() durch das Dateisystem in Bezug auf die begrenzt, wie groß eine Datei, die sie erzeugen können? Wenn ja; Ist das eine Einschränkung von PHP? Passiert das auch in anderen Sprachen?

+0

einige Code anzeigen ... wahrscheinlich es ist, weil Sie auf einem 32-Bit-Betriebssystem sind, und Sie sind overflo wing das int-Limit auf die Dateiposition (aber das ist nur Spekulation, wenn Sie nicht entweder 'ftell' oder' fseek' genannt haben) ... – ircmaxell

+0

Wird Code zeigen, sobald ich aus dem Büro nach Hause komme. – KeatsKelleher

+0

@ircmaxell: fseek() wurde am Ende der Ausführung aufgerufen. – KeatsKelleher

Antwort

6

Was wahrscheinlich passiert, ist die zugrunde liegende PHP-Build ist 32bit und kann nicht mit Dateizeiger> 4GB - siehe related question.

Ihr zugrunde liegendes Betriebssystem ist offensichtlich in der Lage, große Dateien zu speichern, weshalb Sie stdout zu einer großen Datei umleiten können.

Übrigens ist eine SQL-Datei wahrscheinlich stark komprimierbar, daher sollten Sie die Datei gzip fopen wrapper in Betracht ziehen, um die Datei während des Schreibens zu komprimieren.

$file = 'compress.zlib:///path/to/my/file.sql.gz'; 
$f = fopen($file, 'wb'); 

    //just write as normal... 
    fwrite($f, 'CREATE TABLE foo (....)'); 

fclose($f); 

Ihre Dump wird ein Bruchteil der ursprünglichen Größe, und Sie können es einfach wiederherstellen die Ausgabe von zcat in eine SQL-Client-Rohrleitung, z.B. für mysql

zcat /path/to/my/file.sql.gz | mysql mydatabase 
+0

Ich bin auf 32-Bit und ich kann keine Dateien> 2GiB generieren. http://stackoverflow.com/q/19438203/89771 –

2

Ja und nein. Es ist nicht fopen() oder fwrite() die direkt begrenzt sind, es sind die Dateien, die abhängig vom Dateisystem einige Dimensionen nicht überschreiten können. Sehen Sie sich Comparison of filesystems auf Wikipedia an.

+3

Aber wenn das der Fall ist, wie funktioniert die Ausgabeumleitung beim Generieren einer ~ 10 GB Datei für das OP? – Chetan

+0

Warum nicht? Die * f *() * ("File" -Funktionen) funktionieren normalerweise in Streams. Wenn Sie also * fwrite() * aufrufen, puffert es nur bis zu (ich nehme an) 4kB, bevor es die Ausgabe direkt in den offenen Stream schreibt (der Rückgabewert von * fopen() *). Nun wird Ihr Skript ausgeführt und ausgeführt und füllt die Datei, aber irgendwann blockiert das Dateisystem aufgrund der maximalen Dateigröße weitere Daten. In der Tat, ich weiß nicht, ob dir das wirklich passiert, weil 10GB ein ungerader Wert ist. Anyway: Versuchen Sie es in mehrere Dateien zu teilen (von sagen wir <4GB). Sie wissen nicht genau auf FS die Dateien werden später gespeichert. – KingCrunch

0

Ist es möglich, dass Ihr Skript zu lange dauert und ausgeführt wird und das Zeitlimit überschritten ist?

Oder ist es möglich, dass Sie Ihre Speichergrenzen innerhalb des Skripts erreichen?

+0

es wird mit php-cli ausgeführt; Definitiv kein Timeout-Problem. Wenn das Speicherlimit erreicht wurde, wäre eine Fehlermeldung aufgetreten. – KeatsKelleher

+0

gut, dass nixes meine Ideen ... – zzzzBov

0

Sie mehr als 2 GB an Daten in einem Stream schreiben kann, nicht in einer Datei (als fseek internen Zeiger der Datei überschreitet PHP Grenzen, und Ströme in der Regel nicht durchsuchbar)

<? $target = fopen('test.tar', 'w'); //this is a file, limited by php to 2GB $body = str_repeat("===", 1024 * 1024); while(true) fwrite($target, $test);

<? $target = popen('cat > test.tar', 'w'); //this is a stream, no limitation here $body = str_repeat("===", 1024 * 1024); while(true) fwrite($target, $test);