【问题标题】:Recursively search directories and list the x newest files (based on creation date on server)递归搜索目录并列出 x 个最新文件(基于服务器上的创建日期)
【发布时间】:2016-04-02 22:51:25
【问题描述】:

好的,我不完全理解我在这里做什么,所以我想我会得到一些关于我的代码的反馈。

尝试递归搜索我服务器上的特定文件夹,并返回最新添加的 30 个 *.jpg 图像(带有完整文件路径)。

目前,我当前的代码给了我(我假设)时间戳(它们每个看起来都像一串 10 个数字),实际上我似乎只得到了我期望的全部 30 个中的 22 个。我看到另一篇使用 directoryIteratorIterator 的帖子,但我无法为我的服务器升级我的 PHP 版本,也找不到很多明确的文档。

希望有人能在这方面引导我朝着正确的方向前进。

<?php
function get30Latest(){
    $files = array();
    foreach (glob("*/*.jpg") as $filename) {  //I assume "*/*.jpg" would start from the root of the server and go through each directory looking for a match to *.jpg and add to $files array
        $files[$filename] = filemtime($filename);
    }
    arsort($files); //I may not need this since I'm looking to sort by earliest to latest (among the 30 newest images)

    $newest = array_slice($files, 0, 29);  //This should be the first 30 I believe.

    foreach ($newest as $file){ //Assuming I would loop through the array and display the full paths of these 30 images
        echo $file . "</br>"; //Returns something similar to "1451186291, 1451186290, 1451186290, etc..."
    }
}
?>

【问题讨论】:

  • 递归目录迭代器从 PHP v5 开始,所以除非你有 v4.x,否则你可以使用该方法:php.net/manual/en/class.recursivedirectoryiterator.php 该页面上的第一个贡献者注释可能是你需要进行迭代和jpg 的正则表达式。
  • 好的,尝试了第一个贡献者的笔记。工作,所以我想我至少有 v5 PHP。事情进展顺利,但是我只看到打印了“数组”,而不是文件路径。这是我目前所处的位置:function get30Latest(){ $directory = new RecursiveDirectoryIterator('./'); $iterator = new RecursiveIteratorIterator($directory); $regex = new RegexIterator($iterator, '/^.+\.jpg$/i', RecursiveRegexIterator::GET_MATCH); $count = 1; foreach($regex as $file){ echo $count . ":" . " " . $file . "&lt;/br&gt;"; $count++; } }
  • 那么你看到每个文件的路径了吗?喜欢/server/root/html/webroot/images/file.jpg
  • 不,我看到“1:数组,2:数组,3:数组....”
  • 哦,是的,我明白了,这会保存到一个数组中,所以在你的情况下:echo $count . ":" . " " . $file[0] . "&lt;/br&gt;";

标签: php file recursion directory


【解决方案1】:

你走的很好。这应该适合你:

首先,我们创建一个RecursiveDirectoryIterator,将其传递给RecursiveIteratorIterator,这样我们就有了一个迭代器,可以递归地遍历您指定路径的所有文件。我们过滤除 *.jpg 之外的所有文件,并使用 RegexIterator

现在我们可以使用iterator_to_array() 将迭代器转换为数组,这样我们就可以对数组进行排序了。我们将usort()filectime() 结合使用,因此我们比较文件的创建日期并按其排序。

最后,我们可以使用array_slice() 对 30 个最新文件进行切片,我们就完成了。遍历文件并显示它们。

代码:

<?php

    $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("your/path"));
    $rgIt = new RegexIterator($it, "/^.+\.jpg$/i");

    $files = iterator_to_array($rgIt);

    usort($files, function($a, $b){
      if(filectime($a) == filectime($b))
        return 0;
      return filectime($a) > filectime($b) ? -1 : 1;
    });

    $files = array_slice($files, 0 , 30);

    foreach($files as $v)
      echo $v . PHP_EOL;

?>

【讨论】:

  • 关闭。但是,我在第 8 行(在 usort 处)遇到语法错误。它说的是意外的 T_FUNCTION,所以我想知道我服务器上的 PHP 版本是否不支持您传递此类函数的方式,根据我刚刚挖出的这篇文章:link
  • @dotcommer 是的,它是 PHP 版本的东西。匿名函数仅适用于 PHP >= 5.3 (echo PHP_VERSION;)。只需将函数声明为普通函数,为其命名,并将名称作为第二个参数传递给usort()
  • 好的,是不是像function compareFileCTime($a, $b){ if(filectime($a) == filectime($b)) return 0; return filectime($a) &gt; filectime($b) ? -1 : 1; } 然后是usort($files, compareFileCTime())
  • @dotcommer 差不多,只是usort($files, compareFileCTime()) -> usort($files, "compareFileCTime");
  • @dotcommer 1) 我不会包含 PHP 5.3 的代码,因为它不再受支持:php.net/supported-versions.php 2) 此外,如果您有想要通过的单个目录,您可以使用glob()array_merge() 将每个文件夹中的所有文件放在一起,然后您可以使用 preg_grep() 对其进行过滤,然后按照我的回答再次对数组进行排序。或者,如果您想使用迭代器来执行此操作,您可以使用 AppendIterator 创建一个普通的 DirectoryIterator 以将每个目录附加到同一个迭代器,然后您可以按照我的答案将其转换并从那里开始。
【解决方案2】:

我认为你可能想要做的是让你的功能更通用,以防你想将它的功能用于其他用途或只是简单地改变它。然后您不必创建get10Latest()get25Latest() 等。这只是一个简单的类,其中包含您需要获取和返回的所有脚本。使用你想要的,方法是按使用顺序排列的,所以你可以把方法的胆量拿出来创建一个大函数:

class   FetchImages
    {
        private $count  =   30;
        private $arr    =   array();
        private $regex  =   '';
        public  function __construct($filter = array('jpg'))
            {
                // This will create a simple regex from the array of file types ($filter)
                $this->regex    =   '.+\.'.implode('|.+\.',$filter);
            }

        public  function getImgs($dir = './')
            {
                // Borrowed from contributor notes from the RecursiveDirectoryIterator page
                $regex      =   new RegexIterator(
                                new RecursiveIteratorIterator(
                                new RecursiveDirectoryIterator($dir)),
                                '/^'.$this->regex.'$/i',
                                RecursiveRegexIterator::GET_MATCH);
                // Loop and assign datetimes as keys,
                // You don't need date() but it's more readable for troubleshooting
                foreach($regex as $file)
                    $this->arr[date('YmdHis',filemtime($file[0]))][]    =   $file[0];
                // return the object for method chaining
                return $this;
            }

        public  function setMax($max = 30)
            {
                // This will allow for different returned values
                $this->count    =   $max;
                // Return for method chaining
                return $this;
            }

        public  function getResults($root = false)
            {
                if(empty($this->arr))
                    return false;
                // Set default container
                $new    =   array();
                // Depending on your version, you may not have the "SORT_NATURAL"
                // This is what will sort the files from newest to oldest
                // I have not accounted for empty->Will draw error(s) if not array
                krsort($this->arr,SORT_NATURAL);
                // Loop through storage array and make a new storage
                // with single paths
                foreach($this->arr as $timestamp => $files) {
                    for($i = 0; $i < count($files); $i++)
                        $new[]  =   (!empty($root))? str_replace($root,"",$files[$i]) : $files[$i];
                }
                // Return the results
                return (!$this->count)? $new : array_slice($new,0,$this->count);
            }
    }

// Create new instance. I am allowing for multiple look-up
$getImg =   new FetchImages(array("jpg","jpeg","png"));
// Get the results from my core folder
$count  =   $getImg ->getImgs(__DIR__.'/core/')
                    // Sets the extraction limit "false" will return all
                    ->setMax(30)
                    // This will strip off the long path
                    ->getResults(__DIR__);

print_r($count);

【讨论】:

  • 好的,请耐心等待。我将作为答案进行回复,以便您了解我的处理方式。
【解决方案3】:

我真的不需要一个庞大、灵活的函数类。此功能将始终输出最新的 30 张图像。如果我理解正确,您将时间戳作为键分配给数组中的每个文件,然后使用 krsort 按键排序?我正在尝试仅提取这些部分,以获取带有时间戳的文件数组,从最新到最旧排序,然后将数组切片为前 30 个。这只是一个快速尝试作为谈话要点(不完整以任何方式)。目前它只输出一个文件数百次:

<?php
function get30Latest(){
    $directory = new RecursiveDirectoryIterator('./');
    $iterator = new RecursiveIteratorIterator($directory);
    $regex = new RegexIterator($iterator, '/^.+\.jpg$/i', RecursiveRegexIterator::GET_MATCH);

    foreach($regex as $file){
        $tmp->arr[date('YmdHis',filemtime($file[0]))][] = $file[0];
        krsort($tmp->arr,SORT_NATURAL);

        foreach($tmp->arr as $timestamp => $files) {
            for($i = 0; $i < count($files); $i++)
                $new[] = (!empty($root))? str_replace($root,"",$files[$i]) : $files[$i];

            echo $new[0] . "</br>";  //this is just for debugging so I can see what files
                                     //are showing up.  Ideally this will be the array I'll
                                     //pull the first 30 from and then send them off to a
                                     //thumbnail creation function
        }
    }

}
?>

【讨论】:

  • 是的,和我做的差不多,你做的好吗?
  • 不,很遗憾。此代码当前打印出相同图像的长列表,“Image01.jpg, image01.jpg, image01.jpg....”
  • 您缺少 array_slice() 来修剪 $new
猜你喜欢
  • 2013-01-12
  • 2017-06-12
  • 1970-01-01
  • 2012-04-07
  • 2014-07-07
  • 1970-01-01
  • 2017-09-09
  • 2012-06-12
相关资源
最近更新 更多