Menu

PHP fopen(): abrir, leer y escribir archivos (los modos)

fopen('data.txt', 'r') abre un archivo y devuelve un manejador, o false si falla. Lee del manejador con fgets() o fread(), escribe con fwrite() y ciérralo con fclose(). El modo ('r', 'w', 'a', 'x', 'c' y sus formas con +) decide qué puedes hacer.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

fopen('data.txt', 'r') abre un archivo y devuelve un manejador, un recurso de stream que las demás funciones de archivos reciben como primer argumento. Lee con fgets() (una línea) o fread() (un número de bytes), escribe con fwrite() y cierra con fclose(). El segundo argumento es el modo: 'r' para leer, 'w' para escribir, 'a' para añadir.

Salida:

Got: apple
Got: banana
Got: cherry

fopen() devuelve false cuando no puede abrir el archivo (no existe en modo r, falta una carpeta, no hay permiso), y PHP imprime un warning como:

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

Así que comprueba si es false antes de usar el manejador. Para leer o escribir un archivo pequeño entero en una llamada, file_get_contents() y file_put_contents() son más cortas; fopen() es para archivos que lees por partes o mantienes abiertos.

Modos de fopen

ModoLeeEscribeSi el archivo existeSi no existeEmpieza en
rsínolo abrefallael principio
r+sísílo abre, conserva el contenidofallael principio
wnosílo vacíalo creael principio
w+sísílo vacíalo creael principio
anosíconserva el contenidolo creael final, cada escritura añade
a+sísíconserva el contenidolo creael final, cada escritura añade
xnosífallalo creael principio
x+sísífallalo creael principio
cnosíconserva el contenidolo creael principio
c+sísíconserva el contenidolo creael principio

Dos filas sorprenden. r+ escribe sobre los bytes existentes en el sitio, sin insertar, y a+ siempre escribe al final, incluso después de mover el puntero con fseek() (moverlo solo afecta a las lecturas):

Salida:

Xbc
Xbc
Xbc
end

En Windows puedes ver 'rb' o 'wb': la opción b significa binario e impide que Windows traduzca los finales de línea. No hace nada en Linux ni en macOS, así que añadirla es inofensivo y portable.

Leer un archivo línea a línea con fgets()

fgets() devuelve la siguiente línea incluido su \n, y false al final del archivo. Como solo hay una línea en memoria cada vez, este bucle maneja un archivo de log de cualquier tamaño, y puedes parar antes con break:

Salida:

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

Compara con false usando !==, no con un simple while ($line = fgets($fh)): una línea que contenga solo "0" sin salto de línea (la última línea de un archivo puede serlo) es falsy y terminaría el bucle antes de tiempo.

Escribir y añadir con fwrite()

fwrite() escribe una cadena en la posición actual y devuelve el número de bytes escritos, o false si falla. fputs() es la misma función con otro nombre. Abre con 'a' para añadir al final de un archivo sin tocar lo que ya hay:

Salida:

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

PHP_EOL es el final de línea del sistema en el que se ejecuta PHP (\n en Linux y macOS, \r\n en Windows). Para archivos que leen otros programas, elige uno de forma explícita, normalmente "\n".

Leer y escribir archivos CSV con fgetcsv() y fputcsv()

fputcsv() escribe un array como una fila CSV y pone entre comillas los campos que contienen comas, comillas o saltos de línea. fgetcsv() vuelve a leer una fila como array. Pasa de forma explícita el separador, el delimitador y un carácter de escape vacío: eso da un CSV estándar, y PHP 8.4 imprime un aviso de obsolescencia cuando se omite el argumento de escape.

Salida:

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

Dividir las líneas con explode(',', $line) falla en cuanto un campo contiene una coma; fgetcsv() se encarga de las comillas por ti. Para un archivo separado por punto y coma (habitual en las exportaciones de Excel en Europa), pasa ';' como separador.

Moverse por un archivo con fseek(), ftell() y rewind()

Un archivo abierto tiene una posición. Las lecturas y escrituras empiezan ahí y la hacen avanzar. ftell() te dice dónde está, fseek() la mueve a un desplazamiento en bytes y rewind() vuelve al principio. Con w+ puedes escribir un archivo y volver a leerlo con el mismo manejador:

Salida:

11
world
hello world

Bloquear un archivo con flock()

Dos peticiones que leen un contador, le suman uno y lo vuelven a escribir a la vez pueden leer las dos 41 y escribir las dos 42. flock() con LOCK_EX hace que la segunda espere hasta que la primera libere el bloqueo. Aquí el modo adecuado es c+: crea el archivo si hace falta y, a diferencia de w+, no lo vacía antes de que tengas el bloqueo.

Salida:

Visitor number 1
Visitor number 2
Visitor number 3

Los bloqueos son orientativos: solo detienen a otro código que también llame a flock(). Para añadir una línea, file_put_contents($path, $line, FILE_APPEND | LOCK_EX) hace lo mismo en una llamada.

Error frecuente: while (!feof($fh))

Muchos tutoriales antiguos recorren el archivo con feof(). Solo devuelve true después de que una lectura ya haya llegado al final, así que el bucle se ejecuta una vez más que líneas hay y el último fgets() devuelve false:

Salida:

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

Ese false de más se convierte en una fila vacía en un informe o en un elemento vacío en un array. Recorre el archivo con la propia lectura, while (($line = fgets($fh)) !== false), como hacen todos los demás ejemplos de esta página.

Preguntas frecuentes

¿Cuáles son los modos de fopen en PHP?

r lee, w escribe después de vaciar el archivo, a escribe al final, x crea un archivo nuevo y falla si existe, y c escribe sin vaciarlo. Añadir + (r+, w+, a+, x+, c+) permite leer y escribir. Todos los modos salvo r y r+ crean el archivo cuando no existe.

¿Cuál es la diferencia entre w y a en fopen?

w vacía el archivo en cuanto se abre y escribe desde el principio. a conserva el contenido y cada fwrite() va al final del archivo, incluso después de fseek(), lo que lo convierte en el modo para los archivos de log.

¿Cómo leo un archivo CSV en PHP?

Ábrelo con fopen($path, 'r') y llama a fgetcsv() en un bucle: while (($row = fgetcsv($fh, null, ',', '"', '')) !== false) { ... }. Cada llamada devuelve una fila como array de campos, con las comillas y las comas incluidas resueltas por ti.

¿Tengo que llamar a fclose en PHP?

PHP cierra todos los archivos abiertos cuando termina el script, así que un script corto funciona sin él. Llama a fclose() de todos modos en cuanto termines: vuelca las escrituras en búfer, libera los bloqueos tomados con flock() e impide que un script de larga duración se quede sin manejadores de archivo.

Ilustración de los lenguajes de programación de Coddy

Aprende a programar con Coddy

COMENZAR