2010-03-27 3 views
2

J'ai un ensemble de dossiers qui a une profondeur d'au moins 4 ou 5 niveaux. Je cherche à parcourir l'arborescence de répertoires aussi profondément que possible, et parcourir tous les fichiers. J'ai obtenu le code pour descendre dans les premiers sous-répertoires, mais pas plus profond, et je ne sais pas pourquoi. Des idées?Récursivité via une arborescence de répertoires en PHP

$count = 0; 
$dir = "/Applications/MAMP/htdocs/site.com"; 
function recurseDirs($main, $count){ 
    $dir = "/Applications/MAMP/htdocs/site.com"; 
    $dirHandle = opendir($main); 
    echo "here"; 
    while($file = readdir($dirHandle)){ 
     if(is_dir($file) && $file != '.' && $file != '..'){ 
      echo "isdir"; 
      recurseDirs($file); 
     } 
     else{ 
      $count++; 
      echo "$count: filename: $file in $dir/$main \n<br />"; 
     } 
    } 
} 
recurseDirs($dir, $count); 

Répondre

0

L'appel à is_dir et recurseDirs n'est pas entièrement correct. Votre comptage n'a pas fonctionné correctement. Cela fonctionne pour moi:

$dir = "/usr/"; 
function recurseDirs($main, $count=0){ 
    $dirHandle = opendir($main); 
    while($file = readdir($dirHandle)){ 
     if(is_dir($main.$file."/") && $file != '.' && $file != '..'){ 
      echo "Directory {$file}: <br />"; 
      $count = recurseDirs($main.$file."/",$count); // Correct call and fixed counting 
     } 
     else{ 
      $count++; 
      echo "$count: filename: $file in $main \n<br />"; 
     } 
    } 
    return $count; 
} 
$number_of_files = recurseDirs($dir); 

Notez les appels modifiés à la fonction ci-dessus et la nouvelle valeur de retour de la fonction.

17

Consultez le nouveau RecursiveDirectoryIterator.

C'est encore loin d'être parfait car vous ne pouvez pas commander les résultats de la recherche et d'autres choses, mais simplement obtenir une liste de fichiers, c'est bien.

Il y a des exemples simples pour vous aider à démarrer dans le manuel comme celui-ci:

<?php 

$path = realpath('/etc'); 

$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), 
RecursiveIteratorIterator::SELF_FIRST); 

foreach($objects as $name => $object){ 
    echo "$name\n"; 
} 

?> 
+0

Juste une remarque: un itérateur fait ce que son nom l'indique. Il itére sur une source itérable. Ce n'est pas différent d'itérer sur un tableau. Si vous voulez que les résultats soient triés, vous devrez le faire dans la boucle foreach ou écrire/utiliser une fonction pour le faire pour vous. – Gordon

+1

@Gordon vrai. Mais être capable d'obtenir les résultats triés et/ou filtrés tout de suite est une fonctionnalité que j'attendrais néanmoins d'un itérateur de répertoire récursif - je comprends que cela ne soit pas dans l'esprit du SPL, mais quand même. En l'état actuel des choses, il est nécessaire de créer des douzaines de lignes de code (avec des centaines d'extraits sur le réseau, toutes de qualité variable) pour effectuer une tâche standard, où d'autres langages offrent des fonctions toutes prêtes. Ça m'énerve parfois. –

+0

@Pekka Puisque tout peut être un Iterable maintenant, il est impossible de trouver un genre générique. Comment devrait-il savoir que je veux que mes objets Person soient triés par $ firstName mais mes fichiers par MTime? Vous * devez * écrire ceci. Si vous voulez interroger des objets par des expressions génériques, jetez un oeil à PHPLinq. – Gordon

2

Il y a une erreur dans l'appel

recurseDirs($file); 

et

is_dir($file) 

vous Indiquer le chemin complet:

recurseDirs($main . '/' .$file, $count); 

et

is_dir($main . '/' .$file) 

Cependant, comme d'autres anwerers, je suggère d'utiliser RecursiveDirectoryIteretor.

0

Alors ouais: Aujourd'hui, j'étais flemmard et googled pour une solution de coupe de biscuit à une liste de répertoires récursifs et suis tombé sur ceci. Comme j'ai fini par écrire ma propre fonction (pourquoi j'ai même passé du temps à Google pour cela est au-delà de moi - je ressens toujours le besoin de réinventer la roue sans raison valable) je me sentais enclin à partager ma prise sur ce. Bien qu'il y ait des opinions pour et contre l'utilisation de RecursiveDirectoryIterator, je posterai simplement mon opinion sur une simple fonction de répertoire récursif et éviterai les politiques de s'interrompre sur RecursiveDirectoryIterator.

Ici, il est:

function recursiveDirectoryList($root) 
{ 

    /* 
    * this next conditional isn't required for the code to function, but I 
    * did not want double directory separators in the resulting array values 
    * if a trailing directory separator was provided in the root path; 
    * this seemed an efficient manner to remedy said problem easily... 
    */ 
    if(substr($root, -1) === DIRECTORY_SEPARATOR) 
    { 
     $root = substr($root, 0, strlen($root) - 1); 
    } 

    if(! is_dir($root)) return array(); 

    $files = array(); 
    $dir_handle = opendir($root); 

    while(($entry = readdir($dir_handle)) !== false) 
    { 

     if($entry === '.' || $entry === '..') continue; 

     if(is_dir($root . DIRECTORY_SEPARATOR . $entry)) 
     { 
      $sub_files = recursiveDirectoryList( 
       $root . 
       DIRECTORY_SEPARATOR . 
       $entry . 
       DIRECTORY_SEPARATOR 
      ); 
      $files = array_merge($files, $sub_files); 
     } 
     else 
     { 
      $files[] = $root . DIRECTORY_SEPARATOR . $entry; 
     } 
    } 

    return (array) $files; 

} 

Avec cette fonction, la réponse à l'obtention d'un nombre de fichiers est simple:

$dirpath = '/your/directory/path/goes/here/'; 

$files = recursiveDirectoryList($dirpath); 

$number_of_files = sizeof($files); 

Mais, si vous ne voulez pas les frais généraux d'un tableau des chemins de fichier respectifs - ou n'en ont tout simplement pas besoin - il n'est pas nécessaire de transmettre un nombre à la fonction récursive comme cela a été recommandé.

On pourrait simplement modifier ma fonction d'origine pour effectuer le comptage en tant que tel:

function recursiveDirectoryListC($root) 
{ 

    $count = 0; 

    if(! is_dir($root)) return (int) $count; 

    $dir_handle = opendir($root); 

    while(($entry = readdir($dir_handle)) !== false) 
    { 

     if($entry === '.' || $entry === '..') continue; 

     if(is_dir($root . DIRECTORY_SEPARATOR . $entry)) 
     { 
      $count += recursiveDirectoryListC(
       $root . 
       DIRECTORY_SEPARATOR . 
       $entry . 
       DIRECTORY_SEPARATOR 
      ); 
     } 
     else 
     { 
      $count++; 
     } 

    } 

    return (int) $count; 

} 
fonction

la opendir() Dans ces deux fonctions devrait vraiment être enveloppé dans une condition dans le cas où le répertoire est pas lisible ou une autre erreur se produit. Assurez-vous de le faire correctement:

if(($dir_handle = opendir($dir)) !== false) 
{ 
    /* perform directory read logic */ 
} 
else 
{ 
    /* do something on failure */ 
} 

Hope this helps quelqu'un ...

Questions connexes