readdir vs scandir

4 minutos de lectura

avatar de usuario
pensandomono

1]¿Cuál de las funciones es más rápida?
2]¿Cuáles son las diferencias?

Differences

1]readdir devuelve el nombre de la siguiente entrada en el directorio. Scandir devuelve una matriz de archivos y directorios del directorio.

2]readdir debe tener un identificador de recursos abierto hasta que se lean todas las entradas. scandir, ¿tal vez crea una matriz de todas las entradas y cierra el identificador de recursos?

  • posible duplicado de Directory to array con PHP

    – Salathe

    1 de enero de 2012 a las 11:35

Solo obteniendo los resultados (sin hacer nada), readdir es un mínimo más rápido:

<?php

$count = 10000;

$dir="/home/brati";

$startScan = microtime(true);
for ($i=0;$i<$count;$i++) {
    $array = scandir($dir);
}
$endScan = microtime(true);


$startRead = microtime(true);
for ($i=0;$i<$count;$i++) {
    $handle = opendir($dir);
    while (false !== ($entry = readdir($handle))) {
        // We do not know what to do
    }
}
$endRead = microtime(true);

echo "scandir: " . ($endScan-$startScan) . "\n";
echo "readdir: " . ($endRead-$startRead) . "\n";

Da:

== RUN 1 ==
scandir: 5.3707950115204
readdir: 5.006147146225

== RUN 2 ==
scandir: 5.4619920253754
readdir: 4.9940950870514

== RUN 3 ==
scandir: 5.5265231132507
readdir: 5.1714680194855

Entonces, por supuesto, depende de lo que pretendas hacer. Si tiene que escribir otro ciclo con scandir(), será más lento.

Realmente depende de lo que estés haciendo con los datos.

Si está revisando entrada por entrada, debería usar readdirsi realmente necesita tener una lista de las entradas en la memoria, debe usar scandir.

No tiene sentido copiar información en la memoria cuando, de todos modos, la va a usar entrada por entrada. La evaluación perezosa es definitivamente el camino a seguir en ese caso.

me imagino que scandir es solo una envoltura alrededor de lo mismo que readdir está llamando, y por lo tanto sería más lento.

avatar de usuario
Vitaly

Sé que esta pregunta puede no ser real ahora, pero para agregar, hice algunas pruebas (como Aufziehvogel y Sayahan) con una pequeña diferencia: en un directorio con 1,000,000 de archivos pequeños (unos pocos bytes).

$dir = dirname(__FILE__) . '/dir';

$startScan = microtime(true);
$array = scandir($dir);
for ($i = 0, $j = count($array); $i < $j; $i++) {
    // Code
}
$endScan = microtime(true);
unset($array);

$startRead = microtime(true);
$handle = opendir($dir);
while (false !== ($entry = readdir($handle))) {
    // Code
}
$endRead = microtime(true);
unset($handle);
unset($entry);

$startDir = microtime(true);
$files = new DirectoryIterator($dir);
foreach ($files as $file) {
    // Code
}
$endDir = microtime(true);
unset($files);

echo 'scandir:           ', ($endScan - $startScan), PHP_EOL;
echo 'readdir:           ', ($endRead - $startRead), PHP_EOL;
echo 'DirectoryIterator: ', ($endDir - $startDir), PHP_EOL;

Resultados (HDD):

scandir:           1.9403479099274
readdir:           0.79462885856628
DirectoryIterator: 0.5853099822998

Resultados (SSD):

scandir:           0.83593201637268
readdir:           0.35835003852844
DirectoryIterator: 0.28022909164429

CPU: AMD A10-4600M APU con Radeon(tm) HD Graphics (4 núcleos)
MEMORIA: 8G
PHP: 5.6.29

  • ¿Se realizó esta prueba en un sistema Linux o en un sistema Windows?

    – Un hijo de Dios

    16 de marzo de 2018 a las 23:04

  • En un Linux Fedora,

    – Vitaly

    19 de marzo de 2018 a las 5:48

Hizo algunas comparaciones de tiempo más para leer un árbol de directorios completo con muchos archivos y directorios:

  • la llamada tipo de archivo()==”dir” es claramente más rápido que la llamada is_dir()

  • la abrirdir/leerdir las llamadas son mucho más rápidas que RecursiveDirectoryIterator

  • construir el árbol de directorios usando llamadas recursivas profundidad primero o lineal no hace ninguna diferencia

Las pruebas anteriores se realizaron en Windows en SSD local, USB local y unidad de red con resultados consistentes. La ejecución en la unidad de red fue hasta 180 veces más lenta que en las unidades locales, ¡a pesar de que la unidad ReadyNAS es gigabit y, por lo demás, rápida!

El número de entradas manejadas por segundo osciló entre 115 con el código más lento en la unidad de red hasta casi 65 000 para el código más rápido en la unidad USB 3.0, debido al almacenamiento en caché, por supuesto.

Pero la gran diferencia para la unidad de red hace que te preguntes qué sucede dentro de PHP, ya que el simple comando dir y ls en Linux sobre los mismos archivos es mucho más rápido.

Continuará…

He hecho algunas pruebas. (Gracias a Aufziehvogel por la construcción)

$count = 100000;

$dir = dirname(__FILE__);

$startScan = microtime(true);
for ($i=0;$i<$count;$i++) {
    $array = scandir($dir);
}
$endScan = microtime(true);

$startRead = microtime(true);
for ($i=0;$i<$count;$i++) {
    $handle = opendir($dir);
    while (false !== ($entry = readdir($handle))) {
        // We do not know what to do                    
    }
}
$endRead = microtime(true);

$startGlob = microtime(true);
for ($i=0;$i<$count;$i++) {
    $array3 = glob('*');
}
$endGlob = microtime(true);

echo "scandir: " . ($endScan-$startScan) . "\n";
echo "readdir: " . ($endRead-$startRead) . "\n";
echo "glob   : " . ($endGlob-$startGlob) . "\n";

Resultados del servidor Linux:

scandir: 0.82553291320801
readdir: 0.91677618026733
glob   : 0.76309990882874

Esto resulta de 4 núcleos (8 subprocesos) intel E3-1240 Cpu linux + servidor Apache.

Pero los resultados de Windows Servers son opuestos. Servidor Windows + Apache: Intel Q8400 de 4 núcleos (4 subprocesos)

Resultados del servidor de Windows:

$count = 10000; // it was on linux 100000 :)

scandir: 0.61557507515
readdir: 0.614650011063
glob   : 1.92112612724

(La carpeta incluye 13 archivos. Si se aumentan los archivos, los resultados pueden ser diferentes)

¿Ha sido útil esta solución?