问题
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