PHP统计目录及其子目录中的文件总数函数

7
我需要获取一个指定目录下所有JPG文件的总数,包括其所有子目录但不包括子目录的子目录。
目录结构如下:
dir1/ 2个文件 subdir 1/ 8个文件
总计dir1 = 10个文件
dir2/ 5个文件 subdir 1/ 2个文件 subdir 2/ 8个文件
总计dir2 = 15个文件
我有这个函数,但它不能正常工作,因为它只计算最后一个子目录中的文件,并且总数是实际文件数量的两倍。(如果我在最后一个子目录中有40个文件,则会输出80)
```python def count_files(path): count = 0 for root, dirs, files in os.walk(path): for file in files: if file.endswith('.jpg'): count += 1 return count ```
public function count_files($path) { 
global $file_count;

$file_count = 0;
$dir = opendir($path);

if (!$dir) return -1;
while ($file = readdir($dir)) :
    if ($file == '.' || $file == '..') continue;
    if (is_dir($path . $file)) :
        $file_count += $this->count_files($path . "/" . $file);
    else :
        $file_count++;
    endif;
endwhile;

closedir($dir);
return $file_count;
}
6个回答

11

你可以使用RecursiveDirectoryIterator来实现这个功能。

<?php
function scan_dir($path){
    $ite=new RecursiveDirectoryIterator($path);

    $bytestotal=0;
    $nbfiles=0;
    foreach (new RecursiveIteratorIterator($ite) as $filename=>$cur) {
        $filesize=$cur->getSize();
        $bytestotal+=$filesize;
        $nbfiles++;
        $files[] = $filename;
    }

    $bytestotal=number_format($bytestotal);

    return array('total_files'=>$nbfiles,'total_size'=>$bytestotal,'files'=>$files);
}

$files = scan_dir('./');

echo "Total: {$files['total_files']} files, {$files['total_size']} bytes\n";
//Total: 1195 files, 357,374,878 bytes 
?>

@Neoweiter 这个会扫描子目录的子目录,我以为你只想要扫描到子目录层级? - Ja͢ck
@jack,我不会使用子目录,但如果脚本需要查找它,那也不是很重要 ;) - Neoweiter
1
它包含隐藏的快捷链接,如双点..和点。 - bdalina
1
你可以针对is_dir()添加一些内容,以便目录不被计算为文件。 :) - Umar Niazi
为了删除点文件(而不是目录),请更改为: $ite = new RecursiveDirectoryIterator($path,RecursiveDirectoryIterator::SKIP_DOTS); - Duc Manh Nguyen
显示剩余2条评论

7
为了好玩,我已经把这个做好了:
class FileFinder
{
    private $onFound;

    private function __construct($path, $onFound, $maxDepth)
    {
        // onFound gets called at every file found
        $this->onFound = $onFound;
        // start iterating immediately
        $this->iterate($path, $maxDepth);
    }

    private function iterate($path, $maxDepth)
    {
        $d = opendir($path);
        while ($e = readdir($d)) {
            // skip the special folders
            if ($e == '.' || $e == '..') { continue; }
            $absPath = "$path/$e";
            if (is_dir($absPath)) {
                // check $maxDepth first before entering next recursion
                if ($maxDepth != 0) {
                    // reduce maximum depth for next iteration
                    $this->iterate($absPath, $maxDepth - 1);
                }
            } else {
                // regular file found, call the found handler
                call_user_func_array($this->onFound, array($absPath));
            }
        }
        closedir($d);
    }

    // helper function to instantiate one finder object
    // return value is not very important though, because all methods are private
    public static function find($path, $onFound, $maxDepth = 0)
    {
        return new self($path, $onFound, $maxDepth);
    }
}

// start finding files (maximum depth is one folder down) 
$count = $bytes = 0;
FileFinder::find('.', function($file) use (&$count, &$bytes) {
    // the closure updates count and bytes so far
    ++$count;
    $bytes += filesize($file);
}, 1);

echo "Nr files: $count; bytes used: $bytes\n";

你可以传递基本路径、发现处理程序和最大目录深度(-1表示禁用)。找到的处理程序是您在外部定义的函数,它会接收从find()函数给定的路径相对名称。
希望这有助于你理解 :)

1
开发者的回答实际上非常出色!要使其起作用,请按照以下方式使用: System("find . -type f -print | wc -l");

1
error_reporting(E_ALL);

function printTabs($level)
{
    echo "<br/><br/>";
    $l = 0;
    for (; $l < $level; $l++)
        echo ".";
}

function printFileCount($dirName, $init)
{
    $fileCount = 0;
    $st        = strrpos($dirName, "/");
    printTabs($init);
    echo substr($dirName, $st);

    $dHandle   = opendir($dirName);
    while (false !== ($subEntity = readdir($dHandle)))
    {
        if ($subEntity == "." || $subEntity == "..")
            continue;
        if (is_file($dirName . '/' . $subEntity))
        {
            $fileCount++;
        }
        else //if(is_dir($dirName.'/'.$subEntity))
        {
            printFileCount($dirName . '/' . $subEntity, $init + 1);
        }
    }
    printTabs($init);
    echo($fileCount . " files");

    return;
}

printFileCount("/var/www", 0);

刚刚检查了一下,它可以工作。但是结果的对齐方式不好,逻辑是正确的。


0

如果有人想要计算文件和目录的总数。

显示/计算总目录和子目录数量

find . -type d -print | wc -l

显示/计算主目录和子目录中的文件总数

find . -type f -print | wc -l

仅显示/计数当前目录中的文件(不包括子目录)

find . -maxdepth 1 -type f -print | wc -l

显示/计算当前目录中的总目录和文件数(不包括子目录)

ls -1 | wc -l

因为那根本没有回答问题,所以被投下反对票。 - Eugen Mayer

-3

使用for each循环可以更快地完成任务 ;-)

据我记得,opendir是从SplFileObject类派生而来的,该类是一个RecursiveIterator、Traversable、Iterator、SeekableIterator类,因此,如果您使用SPL标准PHP库检索整个子目录中的所有图像计数,则不需要while循环。

但是,我已经有一段时间没有使用PHP了,所以可能会犯错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接