Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

I don't use glob, I use readdir

by Corion (Pope)
on May 29, 2000 at 13:52 UTC ( #15272=note: print w/ replies, xml ) Need Help??


in reply to Getting a List of Files Via Glob

As most of my scripts have to run under Win32, I don't use glob :) (Note: glob() is also available under Win32, but another process must be started that reads the directory in, not really elegant IMO). I use the

DIR = opendir( "$area" ) or die "Can't read '$area' : $!"; @files = readdir( DIR ) or die "Error reading from '$area' : $!"; closedir( DIR ); # Don't care about errors here
combo. If you simply want to process every file in a directory, instead of   @files = readdir(DIR) you could use
while ($file = readdir(DIR)) { ... do your stuff to $file ... }

The drawback of readdir() against glob() is of course, that you have to descend through the directories yourself if you want recursive processing, but I like programs more that give the user some feedback (like painting a dot for each directory traversed as appropriate) ...


Comment on I don't use glob, I use readdir
Select or Download Code
RE: I don't use glob, I use readdir
by merlyn (Sage) on May 29, 2000 at 19:09 UTC
RE: I don't use glob, I use readdir
by t0mas (Priest) on May 30, 2000 at 13:46 UTC
    I often use readdir in a recursive mode, like :
    &makeTree(0,'/where/to/start'); sub makeTree { my ($level,$Dir)=@_; # Get all directories opendir(DIR,$Dir) || die "$!"; my @Dirs = grep { /^[^.].*/ && -d "$Dir/$_" } readdir(DIR); closedir(DIR); # Read files and do stuff or whatever... # Call self foreach my $currDir (@Dirs) { &makeTree($level+1,join('/',$Dir,$currDir)); } };


    /brother t0mas
      In your code, you donīt need to re-read the directory to get at the files in the directory - although it would be difficult to "compute" the difference of the array elegantly (well, difficult to me at least). I mostly use the following way, intermixing files and directories :
      # Untested code - use at your own risk sub handledirectory { my ($directory) = @_; my ($entry, @direntries); opendir( DIR, $directory ) or die "Canīt read $directory : $!\n"; @direntries = readdir( DIR ) or die "Error reading $directory : $! +\n"; closedir DIR; foreach $entry, @direntries { # File::Spec gives us cross-platform path utilities # and comes with every Perl standard distribution require File::Spec; my $fullpath; # skip current and parent directory entries next if $entry =~ /^\.\.?$/; $fullpath = File::Spec->catfile( $directory, $entry ); if (-d $fullpath ) { &handledirectory($fullpath); } elsif ( -f $fullpath ) { # This second call to stat() (implicit in the "-f") # could be done away by using some other short # variable that does caching, but that would maybe # confuse the readers ... ... do stuff ... } else { # something strange ... }; }
        The code I posted was to demonstrate a way to recursive call self, not being very useful in itself... ;-)
        There is more than one way to do it. You could rewinddir and readdir again (with a different grep) on the same handle too..
        But I agree that your solution is beautiful.
        Maybe someone could benchmark some testcases.

        /brother t0mas
RE: I don't use glob, I use readdir
by Zoogie (Curate) on May 30, 2000 at 21:09 UTC
    Hurm... is there a way readdir() will work with specifications like "*.txt" or "dir??.log"?

      readdir() will always read in a complete directory, there is no way around that - and for what I know, there is no function in Perl to hint to the operating system that you are only interested in a certain subset of the files either, as Perl comes from a UNIX background and Unix does not have the notion of wildcards in the file system. Wildcard expansion is always done by the shell under UNIX.

      To accomplish what you want done, you do (untested!) the following :

      opendir DIR, $directory or die "Couldn't open $directory : $!\n"; @files = readdir( DIR ) or die "Couldn't read from $directory : $!\n +"; closedir( DIR ); @files = grep @files, { /\.txt$/ && -f $_ };
      (I hope that this test thing in grep() works the way I want it. The RE part checks if the name ends with ".txt", and the -f part checks if the name corresponds to a file (and not a directory)). Another solution for you could be to let the user specify all files (in UNIX-style) on the command line, there even is a module called GlobArgv, which does wildcard expansion for you automagically (under Win32).

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://15272]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (13)
As of 2014-10-01 09:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    What is your favourite meta-syntactic variable name?














    Results (1 votes), past polls