I need to get a total count of JPG files within a specified directory, including ALL it's subdirectories. No sub-sub directories.
Structure looks like this :
dir1/ 2 files subdir 1/ 8 files
total dir1 = 10 files
dir2/ 5 files subdir 1/ 2 files subdir 2/ 8 files
total dir2 = 15 files
I have this function, which doesn't work fine as it only counts files in the last subdirectory, and total is 2x more than the actual amount of files. (will output 80 if I have 40 files in the last subdir)
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;
}
You could do it like this using the 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
?>
For the fun of it I've whipped this together:
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";
You pass the base path, found handler and maximum directory depth (-1 to disable). The found handler is a function you define outside, it gets passed the path name relative from the path given in the find()
function.
Hope it makes sense and helps you :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With