2012-09-02 17 views
7

Duplicar posibles:
PHP SPL RecursiveDirectoryIterator RecursiveIteratorIterator retrieving the full treePHP ¿Obtener la ruta de cada archivo en la carpeta/subcarpeta en la matriz?

No estoy seguro de por dónde empezar. Pero tengo que obtener las rutas a todos los archivos en una carpeta y todo el contenido de la subcarpeta en las rutas también. Por ejemplo, si tuviera 1 carpeta que tuviera cinco carpetas y cada carpeta tuviera 10 mp3s, etc ... Eso significa que mi matriz debería encontrar 50 rutas a estos archivos.

Más adelante digamos que agregué una carpeta más y tenía 3 carpetas y cada carpeta tenía 10 imágenes.

Mi código ahora necesitaría encontrar 80 rutas y almacenarlas en una matriz.

¿Mi pregunta tiene sentido?

ACTUALIZACIÓN:

Mi puesto deseada a cabo sería tener todos estos caminos almacenados en una matriz.

Pero me gustaría "AMAR" que el código sea dinámico, lo que significa que más adelante agregue 10 carpetas más y cada una tenga 17 subcarpetas y cada carpeta tenga una gran cantidad de contenido diferente. Me gustaría que la matriz contenga las rutas de archivos de todos los archivos. Me parece que esto tiene sentido.

+1

Entiendo la estructura de carpetas que tiene. Ahora, ¿cuál quiere que sea su resultado? ¡Actualice su ** resultado deseado ** en su pregunta! :) –

+0

¿por qué le gustaría hacer eso? Tengo poca experiencia con php pero en mi opinión eso mataría a tu servidor deficiente. ¡Imagine a 5000 personas haciendo las lecturas de su estructura de directorios! – Tanmay

+0

Bueno, porque quiero hacerlo es porque tengo un script en flash as3 que puede descargar un archivo a la vez. Flash no puede descargar una carpeta y sus contenidos, por lo que me gustaría que php cree una cadena de todos los contenidos de las carpetas/subcarpetas y la envíe a Flash y pueda comenzar a descargar el contenido en la aplicación. :) –

Respuesta

23

Lo que busca también se llama directorio recursivo que atraviesa. Lo que significa que está revisando todos los directorios y listando subdirectorios y archivos allí. Si hay un subdirectorio, también se recorre y así sucesivamente, por lo que es recursivo.

Como puedes imaginar, esto es algo común que necesitas cuando escribes un software y PHP te apoya con eso. Ofrece un RecursiveDirectoryIterator para que los directorios se puedan iterar recursivamente y el estándar RecursiveIteratorIterator para realizar el recorrido. A continuación, puede acceder fácilmente a todos los archivos y directorios con un simple iteración, por ejemplo a través foreach:

$rootpath = '.'; 
$fileinfos = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($rootpath) 
); 
foreach($fileinfos as $pathname => $fileinfo) { 
    if (!$fileinfo->isFile()) continue; 
    var_dump($pathname); 
} 

Este ejemplo en primer lugar especifica el directorio en el que quiere realizar el desplazamiento.Yo he estado tomando el actual:

$rootpath = '.'; 

La siguiente línea de código es un poco largo, no una instancia the directory iterator y luego the iterator-iterator manera que la estructura en forma de árbol se puede recorrer en un solo bucle/apartamento :

$fileinfos = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($rootpath) 
); 

Estos $fileinfos son entonces itera con un simple foreach:

foreach($fileinfos as $pathname => $fileinfo) { 

interior de eso, hay una prueba para omitir todos los directorios de salida. Esto se hace utilizando el objeto SplFileInfo que se itera. Es provisto por el iterador de directorio recursivo y contiene muchas propiedades y métodos útiles cuando se trabaja con archivos. También puede, por ejemplo, devolver la extensión de archivo, la información del nombre de base sobre el tamaño y la hora, etc., etc.

if (!$fileinfo->isFile()) continue; 

Finalmente acabo de salida de la ruta que es la ruta completa al archivo:

var_dump($pathname); 

Una salida ejemplar sería el siguiente (en este caso en un sistema operativo Windows):

string(12) ".\.buildpath" 
string(11) ".\.htaccess" 
string(33) ".\dom\xml-attacks\attacks-xml.php" 
string(38) ".\dom\xml-attacks\billion-laughs-2.xml" 
string(36) ".\dom\xml-attacks\billion-laughs.xml" 
string(40) ".\dom\xml-attacks\quadratic-blowup-2.xml" 
string(40) ".\dom\xml-attacks\quadratic-blowup-3.xml" 
string(38) ".\dom\xml-attacks\quadratic-blowup.xml" 
string(22) ".\dom\xmltree-dump.php" 
string(25) ".\dom\xpath-list-tags.php" 
string(22) ".\dom\xpath-search.php" 
string(27) ".\dom\xpath-text-search.php" 
string(29) ".\encrypt-decrypt\decrypt.php" 
string(29) ".\encrypt-decrypt\encrypt.php" 
string(26) ".\encrypt-decrypt\test.php" 
string(13) ".\favicon.ico" 

Si hay un subdirectorio al que no se puede acceder, lo siguiente arrojaría una excepción. Este comportamiento se puede controlar con algunas banderas cuando una instancia del RecursiveIteratorIterator:

$fileinfos = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator('.'), 
    RecursiveIteratorIterator::LEAVES_ONLY, 
    RecursiveIteratorIterator::CATCH_GET_CHILD 
); 

espero que esto era informativo. También puede ajustar esto en una clase propia y también puede proporcionar un FilterIterator para mover la decisión de si un archivo debe aparecer o no en el registro foreach.


El poder de la combinación RecursiveDirectoryIterator y RecursiveIteratorIterator sale de su flexibilidad. Lo que no se cubrió anteriormente se llama FilterIterator s. Pensé que agregué otro ejemplo que está haciendo uso de dos escritos por ellos mismos, colocados uno dentro del otro para combinarlos.

  • Uno es para filtrar todos los archivos y directorios que empiezan por un punto (los que se consideran los archivos ocultos en los sistemas UNIX lo que no debe dar esa información al exterior) y
  • Otro que está filtrando el lista solo para archivos Ese es el cheque que anteriormente era dentro de el foreach.

Otro cambio en este ejemplo de uso es hacer uso de la getSubPathname() function que devuelve el subtrazado partir de ruta_raíz de la iteración, por lo que el que usted está buscando.

También me explícitamente agregar el SKIP_DOTS flag que evita atravesar . y .. (técnicamente no realmente necesario porque los filtros podrían filtrar esos también, ya que son directorios, sin embargo, creo que es más correcto) y la devuelve como caminos como UNIX_PATHS por lo que las cadenas de caminos son caminos siempre Unix, independientemente del sistema operativo subyacente que normalmente es una buena idea si se solicitan esos valores a través de HTTP tarde como en su caso:

$rootpath = '.'; 

$fileinfos = new RecursiveIteratorIterator(
    new FilesOnlyFilter(
     new VisibleOnlyFilter(
      new RecursiveDirectoryIterator(
       $rootpath, 
       FilesystemIterator::SKIP_DOTS 
        | FilesystemIterator::UNIX_PATHS 
      ) 
     ) 
    ), 
    RecursiveIteratorIterator::LEAVES_ONLY, 
    RecursiveIteratorIterator::CATCH_GET_CHILD 
); 

foreach ($fileinfos as $pathname => $fileinfo) { 
    echo $fileinfos->getSubPathname(), "\n"; 
} 

Este ejemplo es similar al anterior uno, aunque cómo el $fileinfos is build está configurado de forma diferente. Especialmente la parte sobre los filtros es nuevo:

new FilesOnlyFilter(
     new VisibleOnlyFilter(
      new RecursiveDirectoryIterator($rootpath, ...) 
     ) 
    ), 

Así que el iterador directorio se pone en un filtro y el filtro en sí se pone en otro filtro. El resto no cambió.

El código para estos filtros es bastante sencillo, trabajan con la función accept que es ya sea true o false que se va a tomar o para filtrar:

class VisibleOnlyFilter extends RecursiveFilterIterator 
{ 
    public function accept() 
    { 
     $fileName = $this->getInnerIterator()->current()->getFileName(); 
     $firstChar = $fileName[0]; 
     return $firstChar !== '.'; 
    } 
} 

class FilesOnlyFilter extends RecursiveFilterIterator 
{ 
    public function accept() 
    { 
     $iterator = $this->getInnerIterator(); 

     // allow traversal 
     if ($iterator->hasChildren()) { 
      return true; 
     } 

     // filter entries, only allow true files 
     return $iterator->current()->isFile(); 
    } 
} 

Y eso es todo de nuevo. Naturalmente, puede utilizar estos filtros para otros casos también. P.ej. si tiene otro tipo de listado de directorio.

Y otra salida ejemplar con la $rootpath corta distancia:

test.html 
test.rss 
tests/test-pad-2.php 
tests/test-pad-3.php 
tests/test-pad-4.php 
tests/test-pad-5.php 
tests/test-pad-6.php 
tests/test-pad.php 
TLD/PSL/C/dkim-regdom.c 
TLD/PSL/C/dkim-regdom.h 
TLD/PSL/C/Makefile 
TLD/PSL/C/punycode.pl 
TLD/PSL/C/test-dkim-regdom.c 
TLD/PSL/C/test-dkim-regdom.sh 
TLD/PSL/C/tld-canon.h 
TLD/PSL/generateEffectiveTLDs.php 

No más .git o .svn recorrido de directorio o lista de archivos como .builtpath o .project.


Nota para FilesOnlyFilter y LEAVES_ONLY: El filtro niega explícitamente el uso de directorios y enlaces basados ​​en el SplFileInfo objeto (only regular files that do exist). Entonces es un filtrado real basado en el sistema de archivos.
Otro método para obtener únicamente entradas que no sean de directorio se envía con RecursiveIteratorIterator debido al valor predeterminado LEAVES_ONLY flag (aquí también se usa en los ejemplos). Este indicador no funciona como un filtro y es independiente del iterador subyacente. Simplemente especifica que la iteración no debe devolver las ramas (aquí: directorios en el caso del iterador del directorio).

+0

¡INCREÍBLE! ¡Guauu! ok, ¿cómo obtendría solo la ruta de acceso sin la cadena (33), etc. y cómo puedo obtener solo el nombre del archivo también? :) –

+0

¿También el nombre de ruta menos el ./ justo antes de él? :) –

+0

Hay varias formas de lograr eso. Puedes "extender" esto con un post-procesamiento dentro del 'foreach', los objetos [' SplFileInfo'] (http://php.net/SplFileInfo) son útiles aquí, los tienes en '$ fileinfo'. Eliminar la baseir es realmente trivial porque es '$ rootpath' más el separador de directorios de sistemas de archivos cuya longitud es normalmente exactamente un carácter. Entonces tienes el 'substr ($ pathname, 2)' aquí. Extenderé la respuesta con otro ejemplo de filtro y agregaré esa operación de subcadena ejemplar. – hakre

2

Los pasos son como tal:

y opendir abrirán la estructura de directorios

$dh = opendir($dir)

lo que viene hacer es leer lo que está allí en $dh

$file = readdir($dh)

se puede encontrar toda la información en el manual php correspondiente a opendir

y buscando en Google para la lectura de la estructura regresaron este

http://www.codingforums.com/showthread.php?t=71882

+0

Impresionante. Gracias. se ve muy bien. Probándolo ahora :) Te contactaremos. –

+0

no hay problema. ¡Disfrutar! – Tanmay

+1

demasiado complicado para algo tan simple, puede hacer esto en 5 líneas de código (7 con corchetes para legibilidad) vea mi respuesta a continuación para obtener el código exacto que necesita – RobertMaysJr

4

Si está en Linux y no le importa la ejecución de un comando shell, se puede hacer todo esto en una sola línea

$path = '/etc/php5/*'; // file filter, you could specify a extension using *.ext 
$files = explode("\n", trim(`find -L $path`)); // -L follows symlinks 

print_r($files); 

Salida:

Array (
     [0] => /etc/php5/apache2 
     [1] => /etc/php5/apache2/php.ini 
     [2] => /etc/php5/apache2/conf.d 
     [3] => /etc/php5/apache2/conf.d/gd.ini 
     [4] => /etc/php5/apache2/conf.d/curl.ini 
     [5] => /etc/php5/apache2/conf.d/mcrypt.ini 
     etc... 
    ) 

La siguiente elección más corta que usa solo PHP es global, pero no analiza los subdirectorios como desee.(Que tendría que recorrer los resultados, utilice is_dir() y luego llamar a la función de su nuevo

http://us3.php.net/glob

$files = dir_scan('/etc/php5/*'); 
print_r($files); 

function dir_scan($folder) { 
    $files = glob($folder); 
    foreach ($files as $f) { 
     if (is_dir($f)) { 
      $files = array_merge($files, dir_scan($f .'/*')); // scan subfolder 
     } 
    } 
    return $files; 
} 

Cada otra manera requiere mucho más código a continuación, debería ser necesario hacer algo tan simple

+0

Punto señalado. ¡Gracias! – Tanmay

+1

:-) No hay problema. Otra cosa interesante de glob es que puedes especificar un filtro diferente (* .txt por ejemplo) y filtrar todos los archivos al mismo tiempo (no solo evitas tener que analizar cada nombre de archivo para verificar las extensiones, no incluso tiene que pasar por encima de ellos en absoluto ya que ya están filtrados) – RobertMaysJr

+0

¿Hay alguna manera de obtenerlo menos el ./ anterior en cada matriz? ¿También puedo obtener una variedad de solo los nombres de los archivos sin la ruta y la extensión ho? Esto es brillante por cierto. –

Cuestiones relacionadas