How to exclude file types from Directory Iterator loop

半腔热情 提交于 2019-12-23 19:14:17

问题


Simple directory iterator that is recursive and shows all files and directories/sub-directories.

I don't see any built in function to exclude certain file types, for instance in the following example I do not want to output any image related files such as .jpg, .png, etc. I know there are several methods of doing this , looking for advice on which would be best.

$scan_it = new RecursiveDirectoryIterator("/example_dir");

 foreach(new RecursiveIteratorIterator($scan_it) as $file) {

  echo $file;
  }

回答1:


Update: Ok, so I'm an idiot. PHP has a builtin for this: pathinfo()

Try this:

$filetypes = array("jpg", "png");
$filetype = pathinfo($file, PATHINFO_EXTENSION);
if (!in_array(strtolower($filetype), $filetypes)) {
  echo $file;
}

Original Answer:

Why not just run substr() on the filename and see if it matches the extension of the file type you want to exclude:

$scan_it = new RecursiveDirectoryIterator("/example_dir");

foreach(new RecursiveIteratorIterator($scan_it) as $file) {
  if (strtolower(substr($file, -4)) != ".jpg" && 
      strtolower(substr($file, -4)) != ".jpg") {
    echo $file;
  }
}

You could make it easier by using regular expressions:

if (!preg_match("/\.(jpg|png)*$/i", $file, $matches)) {
   echo $file;
}

You could even use an array to keep track of your file types:

$filetypes = array("jpg", "png");
if (!preg_match("/\.(" . implode("|", $filetypes) . ")*$/i", $file, $matches)) {
   echo $file;
}



回答2:


From PHP 5.4 can use \RecursiveCallbackFilterIterator

$iterator = new \RecursiveDirectoryIterator(getcwd(), \RecursiveDirectoryIterator::SKIP_DOTS);

$iterator = new \RecursiveCallbackFilterIterator(
  $iterator,
  function ($item) {
    return $item->getExtension() === 'php' ? true : false;
  }
);

Iterator now will contains only PHP files.

 foreach($iterator as $file) {
   echo $file;
 }



回答3:


Cross-posting original answer (also in this question) --

Turning glob into an iterator seems to prefilter more easily than writing a custom FilterIterator. Also note that FilterIterator still steps through each item during iteration, just ignores it, whereas glob doesn't seem to. However, glob seems to include rather than exclude, so may not fit your scenario.

No prefilter:

$dir_iterator = new DirectoryIterator($dir);
$paginated = new LimitIterator($dir_iterator, $page * $perpage, $perpage);

Glob prefilter:

$dir_glob = $dir . '/*.{jpg,gif,png}';

$dir_iterator = new ArrayObject(glob($dir_glob, GLOB_BRACE)); // need to get iterator
$dir_iterator = $dir_iterator->getIterator();
$paginated = new LimitIterator($dir_iterator, $page * $perpage, $perpage);

Then, do your thing:

foreach ($paginated as $file) { ... }

Note that in the case of the DirectoryIterator example, $file will be an instance of SplFileInfo, whereas glob example is just the disk path.


Example FilterIterator extension

class ExtensionFilterIterator extends FilterIterator {
    private $filter;

    public function __construct(Iterator $iterator , $filter) {
        parent::__construct($iterator);
        $this->filter = $filter;
    }

    // the meat and potatoes
    public function accept() {
        $current = $this->getInnerIterator()->current();

        ### global $counter;
        ### print_r(array($counter++, $current)); // this proves it goes through the whole thing, even with limit

    // do your comparison


        // assume path
        if( is_string($current) ) {
            $extension = end( explode('.', $current) );
        }
        // assume DirectoryIterator
        else {
            // $ext = $fileinfo->getExtension(); // http://www.php.net/manual/en/class.splfileinfo.php
            $extension = pathinfo($current->getFilename(), PATHINFO_EXTENSION); // < PHP 5.3.6 -- http://www.php.net/manual/en/splfileinfo.getextension.php
        }

        return !    in_array($extension,$this->filter);
    }
}

Usage:

$dir_iterator = new ExtensionFilterIterator(new DirectoryIterator($dir), array('gif', 'jpg', 'png'));
$paginated = new LimitIterator($dir_iterator, $page * $perpage, $perpage);



回答4:


Expanding on the other answers, you could do the filtering in a cleaner way by specialising RecursiveFilterIterator. Eg, the finfo-based approach:

class MyRecursiveFilterIterator extends RecursiveFilterIterator
{
    private $finfo;

    function __construct(RecursiveIterator $i)
    {
        $this->finfo = new finfo(FILEINFO_MIME_TYPE);
        parent::__construct($i);
    }

    /**
     * Filter out files with a MIME type of image/*
     */
    public function accept()
    {
        $file = $this->current();
        $filetype = $this->finfo->file($file);

        $type_parts = explode("/", $filetype, 2);
        $type = $type_parts[0];

        return ("image" !== $type);
    }

}

$scan_it = new RecursiveDirectoryIterator(".");

foreach (new RecursiveIteratorIterator(
            new MyRecursiveFilterIterator($scan_it)) as $file)
{
    print ("$file\n");
}

Similarly you could use RecursiveRegexIterator if you want to use the filename-based approach.




回答5:


I love examples and here is one

I was looking a way to filter extension.You can include/ exclude extensions.

<?php

$dir_iterator = new RecursiveDirectoryIterator("/path");
$iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST);
// could use CHILD_FIRST if you so wish

foreach ($iterator as $file) {
    echo $file, "\n";
}

?>

$file will be an SplFileInfo class, so you can do powerful stuff really easily:

<?php


foreach ($iterator as $file) {
    if ($file->isFile()) {
        echo $file->getExtension(); //By this you are king and you can access more functions of SplFileInfo
    }
}



?>



回答6:


You can use the finfo_file PHP function that returns information about a file.

The functions in this module try to guess the content type and encoding of a file by looking for certain magic byte sequences at specific positions within the file. While this is not a bullet proof approach the heuristics used do a very good job.

Code

<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$scan_it = new RecursiveDirectoryIterator("/example_dir");

 foreach(new RecursiveIteratorIterator($scan_it) as $file) {
  echo finfo_file($finfo, $file) . "<br/>";
  }
finfo_close($finfo);
?>

The output should be something like:

image/png
directory
image/png
image/svg+xml

Edit

So you can take the non-image files with something like that:

if(!preg_match("/image.*/",finfo_file($finfo, $file)))



回答7:


This is how I would do it:

// Get all files ending with ".php" in folder
$folder = __DIR__ . '/example_dir';

$iterator = new RegexIterator(
    new DirectoryIterator($folder), // You can change this to RecursiveDirectoryIterator it you want
    '/\.php$/i',
    RegexIterator::MATCH
);

/** @var SplFileInfo $field_file */
foreach ($r_iterator as $field_file) {
    echo $field_file->getPathname();
}


来源:https://stackoverflow.com/questions/7141468/how-to-exclude-file-types-from-directory-iterator-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!