Re: quickest way to find number of files in a directory?
by kyle (Abbot) on Mar 27, 2007 at 15:10 UTC
|
my $directory_name = shift || '.';
opendir my $dh, $directory_name
or die "Can't opendir '$directory_name': $!";
my $file_count = scalar grep { -f "$directory_name/$_" } readdir $dh;
closedir $dh or die "Can't closedir: $!";
It's bigger and more complicated than a glob-based solution, but you get nice error messages in case there's problems.
If you're interested in all directory entries (i.e., subdirectories and not just files), you can make the grep match { !m{ \A \.\.? \z}x } instead (so it still skips "." and "..").
Updated to fix a problem helpfully pointed out by Corion. The -f needs to have the directory named explicitly in case it's not the current directory. | [reply] [d/l] [select] |
|
++ to you. That's the way to go.
I like let handles close automatically on block exit (where feasible) and since this snippet fits naturally in a sub, I'd do this:
sub files_in_dir
{
my $dir = shift || '.';
opendir my $dh, $dir or croak "opendir '$dir' - $!";
grep { -f } readdir $dh;
}
It produces the number of files if called in scalar context
and the list of filenames if called in list context.
A word spoken in Mind will reach its own level, in the objective world, by its own weight
| [reply] [d/l] |
Re: quickest way to find number of files in a directory?
by davorg (Chancellor) on Mar 27, 2007 at 15:03 UTC
|
my $dir = 'directory name goes here';
my @files = <$dir/*>;
my $count = @files;
| [reply] [d/l] |
|
| [reply] [d/l] |
|
That depends on your shells. At least under bash, you can use glob() to grab dot files, for example:
print "$_\n" for grep{ -f } glob(".*");
Or probably if you want to grab both dot and non-dot files:
print "$_\n" for grep{ -f } glob("{*,}.*");
Regards,
Xicheng
| [reply] |
|
|
|
is it efficient with more than 100 000 files in the directory ?
if I well understand the code, each inode is loaded in memory... so do you know another mean to get this count, without need of a huge memory ?
| [reply] |
|
That also fails if $dir contains spaces or other glob meta characters.
| [reply] [d/l] |
|
That works very nicely, thank you.
| [reply] |
|
Some people use whitespaces in paths.
Try:
my @files = <'$dir/*'>;
| [reply] |
|
Thanks a lot, that works great.
Does anybody know if it's possible to include variables in the file handle? For example, if I want all the .pl files starting with 'blabla' is it possible to do something like this:
my $prename = 'blabla';
my @files = <$prename*.pl>
my $count = @files
It works with just <*.pl> but I can't get the variable to work.
| [reply] |
|
| [reply] |
|
Re: quickest way to find number of files in a directory?
by johngg (Canon) on Mar 27, 2007 at 15:05 UTC
|
You could try this. It excludes the '.' and '..' links
$ perl -le '
opendir D, q{dirname} or die $!;
print scalar grep { ! m{^\.\.?$} } readdir D;'
123
$
Cheers, JohnGG | [reply] [d/l] |
Re: quickest way to find number of files in a directory?
by izut (Chaplain) on Mar 28, 2007 at 00:16 UTC
|
Depending on the amount of the files you're talking about, maybe File::Find::Rule fit your needs:
use strict;
use warnings;
use File::Find::Rule;
my @files = File::Find::Rule->file()->in('/my/path');
print scalar @files, $/;
Igor 'izut' Sutton
your code, your rules.
| [reply] [d/l] |
|
Are we talking quick, as in coding/thinking time?
` ls -a1 | wc -l`
Well -2 entries for . and ..
| [reply] |
|
Are we talking quick, as in coding/thinking time?
` ls -a1 | wc -l`
| [reply] |
|
Well, you could also do `find /tmp -type f | wc -l`, but I think that backticks are evil. Ah, and we also could free our minds from Perl and write some nasty bash script code :-P.
Igor 'izut' Sutton
your code, your rules.
| [reply] [d/l] |
|
Re: quickest way to find number of files in a directory?
by trizen (Hermit) on Dec 11, 2011 at 02:50 UTC
|
Here is a pretty fast script that finds the number of files and directories in a given path.
#!/usr/bin/perl
use strict;
my $f; # number of files
my $d; # number of dirs
sub count_files {
my ($ref) = @_;
foreach my $dir (@$ref) {
$dir = readlink $dir and chop $dir if -l $dir; # read link
next unless opendir(my $dir_h, $dir); # open dir o
+r next
my @dirs;
while (defined(my $file = readdir $dir_h)) {
if ($file eq '.' or $file eq '..') {
next;
}
if (-d "$dir/$file") {
++$d; # counting d
+irs
push @dirs, "$dir/$file";
}
elsif(-f _){
++$f; # counting f
+iles
}
}
closedir $dir_h;
count_files(\@dirs);
}
[$f, $d];
}
foreach my $arg (@ARGV) {
my @dir = -d $arg ? $arg : next;
($f, $d) = (0, 0);
print "$arg\nFiles\t: $$_[0]\nDirs\t: $$_[1]\n" for count_files(\@
+dir);
}
Usage:
$ time perl test.pl /tmp/ /usr/bin/ /media/
/tmp/
Files : 844
Dirs : 15
/usr/bin/
Files : 1564
Dirs : 3
/media/
Files : 10031
Dirs : 689
real 0m0.111s
user 0m0.030s
sys 0m0.070s
| [reply] [d/l] [select] |
|
Dear trizen,
Thank you very much. I have checked around and so far I can conclude that Your Perl script works correctly and efficiently. Especially, it runs rapidly.
| [reply] |
Re: quickest way to find number of files in a directory?
by pvaldes (Chaplain) on Jul 02, 2012 at 17:51 UTC
|
The quickest way...
This sounds to "inode count" to me...
maybe use Inline C => ... and point your arrows to stat and the inode table?.
I agree, quickest and simplest are not always the same thing... with great speed comes great responsability... and fantastic headaches too
| [reply] |