Traversing directories

A few days ago, I came across a situation where I needed to traverse a multi-level directory structure and operate on all the files.

This can be a bit of a tedious job, as you have to deal with either recursion (nice) or a stack (nicer). I had a feeling there might be something in SPL to take on this task, so I took a peek and ended up with this gem:

<?php
  $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('.'));

  foreach($files as $file) {

    // Do your stuff here, $file is an SplFileInfo object

  }

?>

So how does this work?

I'm going to assume you already know what an Iterator is, if not.. search the interweb.

The DirectoryIterator class can be used to traverse directories, much like scandir() does. The RecursiveDirectoryIterator works the same way, except it implements the hasChildren() and getChildren() methods. hasChildren returns true if the current item has sub-items (in this case, if the item is a directory) and getChildren will return a new iterator for the current subdirectory.

Using this system, we would still need some recursive function to actually go and loop through each subdirectory, this is where RecursiveIteratorIterator comes in. If you pass the RecursiveIteratorIterator any RecursiveIterator object (like RecursiveDirectoryIterator), it will traverse the entire tree for you and pass you all the leaf-nodes.

The leaf nodes are in this context the files. If you also want to make directories part of the traversal, you can change this by passing the constant RecursiveIteratorIterator::SELF_FIRST as the mode parameter.

<?php
  $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('.'),RecursiveIteratorIterator::SELF_FIRST);
?>

Web mentions

Comments

  • andris

    andris

    See more "gems" at http://cvs.php.net/viewvc.cgi/php-src/ext/spl/examples/
  • sapphirecat

    sapphirecat

    If you need to know the path to a file relative to the root directory passed to the RecursiveDirectoryIterator, pass 0 as the flags argument to RDI's constructor. This will give you an RDI instance inside the loop, which has getSubPathname and getSubPath methods in addition to all the SplFileInfo methods. $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root, 0));
  • Anti Veeranna

    Anti Veeranna

    > pass 0 as the flags argument to RDI's constructor According to http://www.php.net/~helly/php/ext/spl/classRecursiveDirectoryIterator.html#be0e1176d512c66500e5c26f248c89c4 you do not need to pass in 0, because __construct() of RDI already uses 0 as default value for flags.
  • Anonymous

    doors.txt;3;6
  • Anonymous

    doors.txt;3;10
  • Anonymous

    doors.txt;3;10
  • Anonymous

    doors.txt;3;10
  • Anonymous

    doors.txt;3;10
  • Anonymous

    doors.txt;3;5