Menu

PHP fopen(): Dateien öffnen, lesen, schreiben (Modi)

fopen('data.txt', 'r') öffnet eine Datei und liefert ein Handle oder bei einem Fehler false. Vom Handle liest du mit fgets() oder fread(), schreibst mit fwrite() und schließt mit fclose(). Der Modus ('r', 'w', 'a', 'x', 'c' und ihre Formen mit +) bestimmt, was du tun kannst.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

fopen('data.txt', 'r') öffnet eine Datei und liefert ein Handle, eine Stream-Ressource, die die anderen Dateifunktionen als erstes Argument nehmen. Du liest mit fgets() (eine Zeile) oder fread() (eine Anzahl Bytes), schreibst mit fwrite() und schließt mit fclose(). Das zweite Argument ist der Modus: 'r' zum Lesen, 'w' zum Schreiben, 'a' zum Anhängen.

Ausgabe:

Got: apple
Got: banana
Got: cherry

fopen() liefert false, wenn es die Datei nicht öffnen kann (sie existiert im Modus r nicht, ein Ordner fehlt, keine Berechtigung), und PHP gibt eine Warnung aus wie:

Warning: fopen(missing.txt): Failed to open stream: No such file or directory in /home/index.php on line 2

Prüfe also auf false, bevor du das Handle verwendest. Um eine ganze kleine Datei mit einem Aufruf zu lesen oder zu schreiben, sind file_get_contents() und file_put_contents() kürzer; fopen() ist für Dateien, die du stückweise liest oder offen hältst.

fopen-Modi

ModusLesenSchreibenWenn die Datei existiertWenn nichtBeginnt am
rjaneinöffnet siescheitertAnfang
r+jajaöffnet sie, behält den InhaltscheitertAnfang
wneinjaleert sielegt sie anAnfang
w+jajaleert sielegt sie anAnfang
aneinjabehält den Inhaltlegt sie anEnde, jedes Schreiben hängt an
a+jajabehält den Inhaltlegt sie anEnde, jedes Schreiben hängt an
xneinjascheitertlegt sie anAnfang
x+jajascheitertlegt sie anAnfang
cneinjabehält den Inhaltlegt sie anAnfang
c+jajabehält den Inhaltlegt sie anAnfang

Zwei Zeilen überraschen. r+ überschreibt die vorhandenen Bytes an Ort und Stelle, ohne einzufügen, und a+ schreibt immer ans Ende, auch nachdem du den Zeiger mit fseek() bewegt hast (das Verschieben wirkt nur aufs Lesen):

Ausgabe:

Xbc
Xbc
Xbc
end

Unter Windows siehst du vielleicht 'rb' oder 'wb': Das Flag b bedeutet binär und verhindert, dass Windows Zeilenenden übersetzt. Unter Linux und macOS bewirkt es nichts, es hinzuzufügen ist also harmlos und portabel.

Eine Datei mit fgets() Zeile für Zeile lesen

fgets() liefert die nächste Zeile einschließlich ihres \n und am Dateiende false. Weil immer nur eine Zeile im Speicher liegt, kommt diese Schleife mit einer Logdatei jeder Größe zurecht, und du kannst mit break früh aufhören:

Ausgabe:

2 errors in 5 lines
line 2: database timeout
line 4: disk full

Vergleiche mit !== auf false, nicht mit einem einfachen while ($line = fgets($fh)): Eine Zeile, die nur "0" ohne Zeilenumbruch enthält (die letzte Zeile einer Datei kann so eine sein), ist falsy und würde die Schleife zu früh beenden.

Mit fwrite() schreiben und anhängen

fwrite() schreibt einen String an der aktuellen Position und liefert die Anzahl der geschriebenen Bytes oder false bei einem Fehler. fputs() ist dieselbe Funktion unter anderem Namen. Öffne mit 'a', um ans Ende einer Datei anzuhängen, ohne anzurühren, was dort steht:

Ausgabe:

wrote 12 bytes
wrote 13 bytes
wrote 15 bytes
visit /home
visit /about
visit /contact
visit /home

PHP_EOL ist das Zeilenende des Systems, auf dem PHP läuft (\n unter Linux und macOS, \r\n unter Windows). Für Dateien, die andere Programme lesen, wählst du eines ausdrücklich, meist "\n".

CSV-Dateien mit fgetcsv() und fputcsv() lesen und schreiben

fputcsv() schreibt ein Array als eine CSV-Zeile und setzt Felder mit Kommas, Anführungszeichen oder Zeilenumbrüchen in Anführungszeichen. fgetcsv() liest eine Zeile als Array zurück. Übergib Trennzeichen, Einschlusszeichen und ein leeres Escape-Zeichen ausdrücklich: Das ergibt Standard-CSV, und PHP 8.4 gibt einen Deprecation-Hinweis aus, wenn das Escape-Argument fehlt.

Ausgabe:

name,city,note
Ada,London,"likes ""math"", a lot"
Linus,Helsinki,kernel

Ada lives in London: likes "math", a lot
Linus lives in Helsinki: kernel

Zeilen mit explode(',', $line) aufzuteilen, scheitert, sobald ein Feld ein Komma enthält; fgetcsv() erledigt die Anführungszeichen für dich. Für eine Datei mit Semikolon als Trennzeichen (in Europa üblich bei Excel-Exporten) übergibst du ';' als Trennzeichen.

Mit fseek(), ftell() und rewind() in einer Datei bewegen

Eine geöffnete Datei hat eine Position. Lese- und Schreibvorgänge beginnen dort und schieben sie weiter. ftell() sagt dir, wo sie steht, fseek() verschiebt sie zu einem Byte-Offset, und rewind() geht zurück an den Anfang. Mit w+ kannst du eine Datei schreiben und über dasselbe Handle zurücklesen:

Ausgabe:

11
world
hello world

Eine Datei mit flock() sperren

Zwei Anfragen, die gleichzeitig einen Zähler lesen, eins addieren und zurückschreiben, können beide 41 lesen und beide 42 schreiben. flock() mit LOCK_EX lässt die zweite warten, bis die erste die Sperre freigibt. Der Modus c+ ist hier der richtige: Er legt die Datei bei Bedarf an und leert sie, anders als w+, nicht, bevor du die Sperre hältst.

Ausgabe:

Visitor number 1
Visitor number 2
Visitor number 3

Sperren sind nur beratend: Sie halten nur anderen Code auf, der ebenfalls flock() aufruft. Um eine Zeile anzuhängen, macht file_put_contents($path, $line, FILE_APPEND | LOCK_EX) dasselbe in einem Aufruf.

Typischer Fehler: while (!feof($fh))

Viele alte Tutorials laufen mit feof() in einer Schleife. Es liefert erst true, nachdem ein Lesevorgang schon auf das Ende gestoßen ist, also läuft die Schleife einmal öfter, als es Zeilen gibt, und das letzte fgets() liefert false:

Ausgabe:

string(2) "a
"
string(2) "b
"
string(2) "c
"
bool(false)
4 rounds for 3 lines

Dieses zusätzliche false wird zu einer leeren Zeile in einem Bericht oder einem leeren Element in einem Array. Steuere die Schleife über den Lesevorgang selbst, while (($line = fgets($fh)) !== false), wie es jedes andere Beispiel auf dieser Seite tut.

Häufig gestellte Fragen

Welche fopen-Modi gibt es in PHP?

r liest, w schreibt, nachdem die Datei geleert wurde, a schreibt ans Ende, x legt eine neue Datei an und scheitert, wenn sie existiert, und c schreibt, ohne sie zu leeren. Ein angehängtes + (r+, w+, a+, x+, c+) erlaubt Lesen und Schreiben. Jeder Modus außer r und r+ legt die Datei an, wenn sie fehlt.

Was ist der Unterschied zwischen w und a bei fopen?

w leert die Datei, sobald sie geöffnet wird, und schreibt ab dem Anfang. a behält den Inhalt, und jedes fwrite() geht ans Ende der Datei, auch nach fseek(), und das macht ihn zum Modus für Logdateien.

Wie lese ich in PHP eine CSV-Datei?

Öffne sie mit fopen($path, 'r') und rufe fgetcsv() in einer Schleife auf: while (($row = fgetcsv($fh, null, ',', '"', '')) !== false) { ... }. Jeder Aufruf liefert eine Zeile als Array von Feldern, wobei Anführungszeichen und eingebettete Kommas für dich behandelt werden.

Muss ich in PHP fclose aufrufen?

PHP schließt jede offene Datei, wenn das Skript endet, also funktioniert ein kurzes Skript auch ohne. Rufe fclose() trotzdem auf, sobald du fertig bist: Es schreibt gepufferte Daten weg, gibt mit flock() gesetzte Sperren frei und verhindert, dass einem lang laufenden Skript die Datei-Handles ausgehen.

Illustration der Programmiersprachen bei Coddy

Lerne mit Coddy zu programmieren

LOS GEHT'S