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;
}
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
";
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 :)
A for each loops could do the trick more quickly ;-)
As I remember, opendir is derivated from the SplFileObject class which is a RecursiveIterator , Traversable , Iterator , SeekableIterator class, so, you don't need a while loops if you use the SPL standard PHP Library to retrive the whole images count even on subdirectory.
But, it's been a while that I didn't used PHP so I might made a mistake.
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
";
//Total: 1195 files, 357,374,878 bytes
?>
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);
Just checked, it's working. But the alignment of results is bad,logic works
if anyone is looking to count total number of files and directories.
Show/count total dir and sub dir count
find . -type d -print | wc -l
Show/count total number of files in main and sub dir
find . -type f -print | wc -l
Show/count only files from current dir (no sub dir)
find . -maxdepth 1 -type f -print | wc -l
Show/count total directories and files in current dir (no sub dir)
ls -1 | wc -l
The answer by Developer is actually brilliant! Use it like this to make it work:
System("find . -type f -print | wc -l");