如何从目录迭代器循环中排除文件类型

发布于 2024-11-30 23:26:22 字数 333 浏览 0 评论 0原文

简单的递归目录迭代器,显示所有文件和目录/子目录。

我没有看到任何内置函数来排除某些文件类型,例如在下面的示例中,我不想输出任何与图像相关的文件,例如 .jpg.png 等。我知道有几种方法可以做到这一点,正在寻找最好的建议。

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

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

  echo $file;
  }

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;
  }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

[旋木] 2024-12-07 23:26:22

更新:
好吧,所以我是个白痴。 PHP 有一个内置函数:pathinfo()

试试这个:

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

原始答案:

为什么不直接在文件名上运行 substr() 看看是否可以它与您要排除的文件类型的扩展名匹配:

$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;
  }
}

您可以使用正则表达式使其变得更容易:

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

您甚至可以使用数组来跟踪文件类型:

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

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;
}
二智少女猫性小仙女 2024-12-07 23:26:22

从 PHP 5.4 开始,可以使用 \RecursiveCallbackFilterIterator

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

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

迭代器现在将仅包含 PHP 文件。

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

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;
 }
猫卆 2024-12-07 23:26:22

交叉发布原始答案也在 这个问题) -

glob 转换为迭代器似乎比编写自定义 FilterIterator。另请注意,FilterIterator 在迭代过程中仍然会遍历每个项目,只是忽略它,而 glob 似乎不会。 但是glob 似乎包含而不是排除,因此可能不适合您的场景。

无预过滤器:

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

Glob 预过滤器:

$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);

然后,做你的事情:

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

请注意,在 DirectoryIterator 示例中, $file 将是 SplFileInfo,而 glob 示例只是磁盘路径。


示例FilterIterator扩展

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);
    }
}

用法:

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

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);
紙鸢 2024-12-07 23:26:22

扩展其他答案,您可以通过专门 递归过滤器迭代器。例如,基于 finfo 的方法:

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");
}

同样,如果需要,您可以使用 RecursiveRegexIterator使用基于文件名的方法。

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.

南城追梦 2024-12-07 23:26:22

我喜欢示例,这是

我正在寻找一种过滤扩展名的方法。您可以包含/排除扩展名。

<?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 将是一个 SplFileInfo 类,因此您可以非常轻松地执行强大的操作:

<?php


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



?>

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
    }
}



?>
往昔成烟 2024-12-07 23:26:22

您可以使用 finfo_file PHP 函数返回有关文件的信息。

此模块中的函数尝试通过在文件内特定位置查找某些魔术字节序列来猜测文件的内容类型和编码。虽然这不是万无一失的方法,但所使用的启发式方法效果非常好。

代码

<?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);
?>

输出应该类似于:

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

编辑

因此您可以使用类似的内容获取非图像文件:

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

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)))
难理解 2024-12-07 23:26:22

我就是这样做的:

// 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();
}

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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文