PHP
Manejo de archivos
Buscar..
Sintaxis
- int readfile (cadena $ nombre de archivo [, bool $ use_include_path = falso [, recurso $ contexto]])
Parámetros
Parámetro | Descripción |
---|---|
nombre del archivo | El nombre del archivo que se está leyendo. |
use_include_path | Puede usar el segundo parámetro opcional y establecerlo en VERDADERO, si desea buscar el archivo en la ruta de inclusión, también. |
contexto | Un recurso de flujo de contexto. |
Observaciones
Sintaxis de nombre de archivo
La mayoría de los nombres de archivos pasados a las funciones en este tema son:
- Cuerdas en la naturaleza.
- Los nombres de los archivos se pueden pasar directamente. Si se pasan valores de otros tipos, se convierten en cadena. Esto es especialmente útil con
SplFileInfo
, que es el valor en la iteración deDirectoryIterator
.
- Los nombres de los archivos se pueden pasar directamente. Si se pasan valores de otros tipos, se convierten en cadena. Esto es especialmente útil con
- Relativo o absoluto.
- Pueden ser absolutos. En sistemas similares a Unix, las rutas absolutas comienzan con
/
, por ejemplo,/home/user/file.txt
, mientras que en Windows, las rutas absolutas comienzan con la unidad, por ejemplo,C:/Users/user/file.txt
- También pueden ser relativos, lo que depende del valor de
getcwd
y está sujeto a cambios porchdir
.
- Pueden ser absolutos. En sistemas similares a Unix, las rutas absolutas comienzan con
- Aceptar protocolos.
- Pueden comenzar con el
scheme://
para especificar el envoltorio de protocolo para administrar. Por ejemplo,file_get_contents("http://example.com")
recupera contenido de http://example.com .
- Pueden comenzar con el
- Slash-compatible.
- Si bien
DIRECTORY_SEPARATOR
en Windows es una barra invertida y el sistema devuelve barras diagonales para las rutas de forma predeterminada, el desarrollador puede seguir utilizando/
como el separador de directorios. Por lo tanto, por compatibilidad, los desarrolladores pueden usar/
as separadores de directorio en todos los sistemas, pero tenga en cuenta que los valores devueltos por las funciones (por ejemplo,realpath
) pueden contener barras diagonales inversas.
- Si bien
Eliminar archivos y directorios
Borrando archivos
La función de unlink
elimina un solo archivo y devuelve si la operación se realizó correctamente.
$filename = '/path/to/file.txt';
if (file_exists($filename)) {
$success = unlink($filename);
if (!$success) {
throw new Exception("Cannot delete $filename");
}
}
Eliminando directorios, con borrado recursivo.
Por otro lado, los directorios deben eliminarse con rmdir
. Sin embargo, esta función solo borra los directorios vacíos. Para eliminar un directorio con archivos, elimine primero los archivos en los directorios. Si el directorio contiene subdirectorios, puede ser necesaria la recursión .
El siguiente ejemplo escanea archivos en un directorio, borra archivos / directorios miembros de forma recursiva y devuelve la cantidad de archivos (no directorios) eliminados.
function recurse_delete_dir(string $dir) : int {
$count = 0;
// ensure that $dir ends with a slash so that we can concatenate it with the filenames directly
$dir = rtrim($dir, "/\\") . "/";
// use dir() to list files
$list = dir($dir);
// store the next file name to $file. if $file is false, that's all -- end the loop.
while(($file = $list->read()) !== false) {
if($file === "." || $file === "..") continue;
if(is_file($dir . $file)) {
unlink($dir . $file);
$count++;
} elseif(is_dir($dir . $file)) {
$count += recurse_delete_dir($dir . $file);
}
}
// finally, safe to delete directory!
rmdir($dir);
return $count;
}
Funciones de conveniencia
Raw directo IO
file_get_contents
y file_put_contents
brindan la capacidad de leer / escribir desde / a un archivo a / desde una cadena PHP en una sola llamada.
file_put_contents
también se puede usar con el FILE_APPEND
máscara de bits FILE_APPEND
para adjuntar, en lugar de truncar y sobrescribir, el archivo. Se puede usar junto con la máscara de bits LOCK_EX
para adquirir un bloqueo exclusivo del archivo mientras se continúa con la escritura. Banderas de máscara de bits se pueden unir con el |
operador en modo bit-OR.
$path = "file.txt";
// reads contents in file.txt to $contents
$contents = file_get_contents($path);
// let's change something... for example, convert the CRLF to LF!
$contents = str_replace("\r\n", "\n", $contents);
// now write it back to file.txt, replacing the original contents
file_put_contents($path, $contents);
FILE_APPEND
es útil para LOCK_EX
archivos de registro, mientras que LOCK_EX
ayuda a prevenir la condición de carrera de la escritura de archivos desde múltiples procesos. Por ejemplo, para escribir en un archivo de registro sobre la sesión actual:
file_put_contents("logins.log", "{$_SESSION["username"]} logged in", FILE_APPEND | LOCK_EX);
CSV IO
fgetcsv($file, $length, $separator)
El fgetcsv
analiza la línea desde el archivo abierto que comprueba los campos csv. Devuelve campos CSV en una matriz en caso de éxito o FALSE
en caso de error.
Por defecto, solo leerá una línea del archivo CSV.
$file = fopen("contacts.csv","r");
print_r(fgetcsv($file));
print_r(fgetcsv($file,5," "));
fclose($file);
contacts.csv
Kai Jim, Refsnes, Stavanger, Norway
Hege, Refsnes, Stavanger, Norway
Salida:
Array
(
[0] => Kai Jim
[1] => Refsnes
[2] => Stavanger
[3] => Norway
)
Array
(
[0] => Hege,
)
Leyendo un archivo a stdout directamente
readfile
copia un archivo al búfer de salida. readfile () no presentará ningún problema de memoria, incluso al enviar archivos grandes, por su cuenta.
$file = 'monkey.gif';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
O desde un puntero de archivo
Alternativamente, para buscar un punto en el archivo para comenzar a copiar a la salida fpassthru
, use fpassthru
en fpassthru
lugar. En el siguiente ejemplo, los últimos 1024 bytes se copian en la salida estándar:
$fh = fopen("file.txt", "rb");
fseek($fh, -1024, SEEK_END);
fpassthru($fh);
Leyendo un archivo en una matriz
file
devuelve las líneas en el archivo pasado en una matriz. Cada elemento de la matriz corresponde a una línea en el archivo, con la nueva línea aún adjunta.
print_r(file("test.txt"));
test.txt
Welcome to File handling
This is to test file handling
Salida:
Array
(
[0] => Welcome to File handling
[1] => This is to test file handling
)
Obteniendo información del archivo
Compruebe si una ruta es un directorio o un archivo
La función is_dir
devuelve si el argumento es un directorio, mientras que is_file
devuelve si el argumento es un archivo. Use file_exists
para verificar si es cualquiera de los dos.
$dir = "/this/is/a/directory";
$file = "/this/is/a/file.txt";
echo is_dir($dir) ? "$dir is a directory" : "$dir is not a directory", PHP_EOL,
is_file($dir) ? "$dir is a file" : "$dir is not a file", PHP_EOL,
file_exists($dir) ? "$dir exists" : "$dir doesn't exist", PHP_EOL,
is_dir($file) ? "$file is a directory" : "$file is not a directory", PHP_EOL,
is_file($file) ? "$file is a file" : "$file is not a file", PHP_EOL,
file_exists($file) ? "$file exists" : "$file doesn't exist", PHP_EOL;
Esto da:
/this/is/a/directory is a directory
/this/is/a/directory is not a file
/this/is/a/directory exists
/this/is/a/file.txt is not a directory
/this/is/a/file.txt is a file
/this/is/a/file.txt exists
Comprobando el tipo de archivo
Use filetype
para verificar el tipo de archivo, que puede ser:
-
fifo
-
char
-
dir
-
block
-
link
-
file
-
socket
-
unknown
Pasando el nombre del filetype
directamente al tipo de filetype
:
echo filetype("~"); // dir
Tenga en cuenta que el tipo de filetype
devuelve false y activa un E_WARNING
si el archivo no existe.
Comprobando legibilidad y capacidad de escritura
Al pasar el nombre del archivo a las funciones is_writable
e is_readable
, verifique si el archivo se puede escribir o leer respectivamente.
Las funciones devuelven false
gracia si el archivo no existe.
Comprobando el acceso a los archivos / modificar el tiempo
El uso de filemtime
y fileatime
devuelve la marca de tiempo de la última modificación o acceso del archivo. El valor de retorno es una marca de tiempo de Unix; consulte Trabajar con fechas y hora para obtener más detalles.
echo "File was last modified on " . date("Y-m-d", filemtime("file.txt"));
echo "File was last accessed on " . date("Y-m-d", fileatime("file.txt"));
Obtener partes de ruta con fileinfo
$fileToAnalyze = ('/var/www/image.png');
$filePathParts = pathinfo($fileToAnalyze);
echo '<pre>';
print_r($filePathParts);
echo '</pre>';
Este ejemplo dará como resultado:
Array
(
[dirname] => /var/www
[basename] => image.png
[extension] => png
[filename] => image
)
Que se puede utilizar como:
$filePathParts['dirname']
$filePathParts['basename']
$filePathParts['extension']
$filePathParts['filename']
Parámetro | Detalles |
---|---|
$ camino | La ruta completa del archivo a analizar |
$ opción | Una de las cuatro opciones disponibles [PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION o PATHINFO_FILENAME] |
- Si no se pasa una opción (el segundo parámetro), se devuelve una matriz asociativa, de lo contrario se devuelve una cadena.
- No valida que el archivo exista.
- Simplemente analiza la cadena en partes. No se realiza ninguna validación en el archivo (sin verificación de tipo mime, etc.)
- La extensión es simplemente la última extensión de
$path
La ruta para el archivoimage.jpg.png
sería.png
incluso si técnicamente es un archivo.jpg
. Un archivo sin una extensión no devolverá un elemento de extensión en la matriz.
Minimiza el uso de la memoria al tratar con archivos grandes
Si necesitamos analizar un archivo grande, por ejemplo, un CSV de más de 10 Mbytes que contiene millones de filas, algunos utilizan las funciones file
o file_get_contents
y terminan con la configuración de memory_limit
con
Tamaño de memoria permitido de XXXXX bytes agotado
error. Considere la siguiente fuente (top-1m.csv tiene exactamente 1 millón de filas y tiene aproximadamente 22 Mbytes de tamaño)
var_dump(memory_get_usage(true));
$arr = file('top-1m.csv');
var_dump(memory_get_usage(true));
Esto produce:
int(262144)
int(210501632)
porque el intérprete necesitaba mantener todas las filas en la matriz $arr
, por lo que consumía ~ 200 Mbytes de RAM. Tenga en cuenta que ni siquiera hemos hecho nada con el contenido de la matriz.
Ahora considere el siguiente código:
var_dump(memory_get_usage(true));
$index = 1;
if (($handle = fopen("top-1m.csv", "r")) !== FALSE) {
while (($row = fgetcsv($handle, 1000, ",")) !== FALSE) {
file_put_contents('top-1m-reversed.csv',$index . ',' . strrev($row[1]) . PHP_EOL, FILE_APPEND);
$index++;
}
fclose($handle);
}
var_dump(memory_get_usage(true));
que salidas
int(262144)
int(262144)
por lo tanto, no utilizamos un solo byte extra de memoria, sino que analizamos todo el CSV y lo guardamos en otro archivo invirtiendo el valor de la segunda columna. Esto se debe a que fgetcsv
lee solo una fila y $row
se sobrescribe en cada bucle.
Archivo basado en flujo IO
Abriendo un arroyo
fopen
abre un identificador de flujo de archivos, que se puede usar con varias funciones para leer, escribir, buscar y otras funciones encima de él. Este valor es de tipo de resource
y no se puede pasar a otros subprocesos que conservan su funcionalidad.
$f = fopen("errors.log", "a"); // Will try to open errors.log for writing
El segundo parámetro es el modo del flujo de archivos:
Modo | Descripción |
---|---|
r | Abrir en modo de solo lectura, comenzando desde el principio del archivo |
r+ | Abierto para lectura y escritura, comenzando desde el principio del archivo. |
w | Abierto solo para escritura, comenzando desde el principio del archivo. Si el archivo existe, vaciará el archivo. Si no existe intentará crearlo. |
w+ | Abierto para lectura y escritura, comenzando desde el principio del archivo. Si el archivo existe, vaciará el archivo. Si no existe intentará crearlo. |
a | abra un archivo solo para escritura, comenzando al final del archivo. Si el archivo no existe, intentará crearlo. |
a+ | abra un archivo para leer y escribir, comenzando al final del archivo. Si el archivo no existe, intentará crearlo. |
x | crear y abrir un archivo para escritura solamente. Si el archivo existe la llamada fopen fallará |
x+ | Crea y abre un archivo para leer y escribir. Si el archivo existe la llamada fopen fallará |
c | abrir el archivo para la escritura solamente. Si el archivo no existe, intentará crearlo. Comenzará a escribir al principio del archivo, pero no vaciará el archivo antes de escribir. |
c+ | Abre el archivo para leer y escribir. Si el archivo no existe, intentará crearlo. Comenzará a escribir al principio del archivo, pero no vaciará el archivo antes de escribir. |
Al agregar una t
detrás del modo (por ejemplo, a+b
, wt
, etc.) en Windows se traducirán los finales de línea "\n"
a "\r\n"
cuando se trabaje con el archivo. Agregue b
detrás del modo si esto no está destinado, especialmente si es un archivo binario.
La aplicación PHP debe cerrar las secuencias utilizando fclose
cuando ya no se utilizan para evitar el error Too many open files
. Esto es particularmente importante en los programas CLI, ya que las transmisiones solo se cierran cuando se cierra el tiempo de ejecución, lo que significa que en los servidores web puede que no sea necesario (pero aún debería , como práctica para evitar la pérdida de recursos) cerrar las transmisiones. si no espera que el proceso se ejecute durante mucho tiempo y no abrirá muchas secuencias.
Leyendo
Usando fread
leerá el número dado de bytes desde el puntero del archivo, o hasta que se cumpla un EOF.
Líneas de lectura
El uso de fgets
leerá el archivo hasta que se alcance un EOL, o se lea la longitud dada.
Tanto fread
como fgets
moverán el puntero del archivo mientras lee.
Leyendo todo lo que queda
El uso de stream_get_contents
hará que todos los bytes restantes en el flujo en una cadena y lo devuelvan.
Ajuste de la posición del puntero del archivo
Inicialmente, después de abrir el flujo, el puntero del archivo está al principio del archivo (o al final, si se usa el modo a
). El uso de la función fseek
moverá el puntero del archivo a una nueva posición, en relación con uno de los tres valores:
-
SEEK_SET
: este es el valor predeterminado; el desplazamiento de posición del archivo será relativo al principio del archivo. -
SEEK_CUR
: El desplazamiento de la posición del archivo será relativo a la posición actual. -
SEEK_END
: El desplazamiento de posición del archivo será relativo al final del archivo. Pasar un desplazamiento negativo es el uso más común para este valor; moverá la posición del archivo al número especificado de bytes antes del final del archivo.
rewind
es un atajo de conveniencia de fseek($fh, 0, SEEK_SET)
.
El uso de ftell
mostrará la posición absoluta del puntero del archivo.
Por ejemplo, el siguiente script lee omite los primeros 10 bytes, lee los siguientes 10 bytes, omite 10 bytes, lee los siguientes 10 bytes y luego los últimos 10 bytes en file.txt:
$fh = fopen("file.txt", "rb");
fseek($fh, 10); // start at offset 10
echo fread($fh, 10); // reads 10 bytes
fseek($fh, 10, SEEK_CUR); // skip 10 bytes
echo fread($fh, 10); // read 10 bytes
fseek($fh, -10, SEEK_END); // skip to 10 bytes before EOF
echo fread($fh, 10); // read 10 bytes
fclose($fh);
Escritura
El uso de fwrite
escribe la cadena proporcionada en el archivo comenzando en el puntero del archivo actual.
fwrite($fh, "Some text here\n");
Mover y copiar archivos y directorios
Copiando documentos
copy
copia el archivo de origen en el primer argumento al destino en el segundo argumento. El destino resuelto debe estar en un directorio que ya esté creado.
if (copy('test.txt', 'dest.txt')) {
echo 'File has been copied successfully';
} else {
echo 'Failed to copy file to destination given.'
}
Copiando directorios, con recursion.
Copiar directorios es muy similar a eliminar directorios, excepto que para copy
archivos en lugar de unlink
se usa, mientras que para directorios, mkdir
lugar de rmdir
se usa al principio en lugar de estar al final de la función.
function recurse_delete_dir(string $src, string $dest) : int {
$count = 0;
// ensure that $src and $dest end with a slash so that we can concatenate it with the filenames directly
$src = rtrim($dest, "/\\") . "/";
$dest = rtrim($dest, "/\\") . "/";
// use dir() to list files
$list = dir($src);
// create $dest if it does not already exist
@mkdir($dest);
// store the next file name to $file. if $file is false, that's all -- end the loop.
while(($file = $list->read()) !== false) {
if($file === "." || $file === "..") continue;
if(is_file($src . $file)) {
copy($src . $file, $dest . $file);
$count++;
} elseif(is_dir($src . $file)) {
$count += recurse_copy_dir($src . $file, $dest . $file);
}
}
return $count;
}
Renombrando / Moviendo
Renombrar / Mover archivos y directorios es mucho más simple. Se pueden mover o renombrar directorios completos en una sola llamada, usando la función de rename
.
rename("~/file.txt", "~/file.html");
rename("~/dir", "~/old_dir");
rename("~/dir/file.txt", "~/dir2/file.txt");