Processing All Files in a Directory (Perl Cookbook, 2nd Edition)

## 9.5. Processing All Files in a Directory

### 9.5.1. Problem

You want to do something to each file in a particular directory.

### 9.5.2. Solution

Use `opendir` to open the directory and `readdir` to retrieve every filename:

>     opendir(DIR, $dirname) or die "can't opendir $dirname: $!";
>     while (defined($file = readdir(DIR))) {
>         # do something with "$dirname/$file"
>     }
>     closedir(DIR);

### 9.5.3. Discussion

The `opendir`, `readdir`, and `closedir` functions operate on directories as `open`, `<>`, and `close` operate on files. Both use handles, but the directory handles used by `opendir` and friends are different from the filehandles used by `open` and friends. In particular, you can't use `<>` on a directory handle.

In scalar context, `readdir` returns the next filename in the directory until it reaches the end of the directory, when it returns `undef`. In list context it returns the rest of the filenames in the directory or an empty list if there were no files left. As explained in this chapter's Introduction, the filenames returned by `readdir` do not include the directory name. When you work with the filenames returned by `readdir`, you must either move to the right directory first or prepend the directory to the filename.

This shows one way of prepending:

>     $dir = "/usr/local/bin";
>     print "Text files in $dir are:\n";
>     opendir(BIN, $dir) or die "Can't open $dir: $!";
>     while( $file = readdir BIN) {
>         print "$file\n" if -T "$dir/$file";
>     }
>     closedir(BIN);

The `readdir` function will return the special directories "`.`" (the directory itself) and "`..`" (the parent of the directory). Most people skip those files with code like:

>     while ( defined ($file = readdir BIN) ) {
>         next if $file =~ /^\.\.?$/;     # skip . and ..
>         # ...
>     }

Like filehandles, bareword directory handles are per-package constructs. You can use the `local` `*DIRHANDLE` syntax to get a new bareword directory handle. Alternatively, pass an undefined scalar as the first argument to `opendir` and Perl will put a new indirect directory handle into that scalar:

>     opendir my $dh, $directory or die;
>     while (defined ($filename = readdir($dh))) {
>       # ...
>     }
>     closedir $dh;

Or, finally, you can use `DirHandle` to get an object-oriented view of a directory handle. The following code uses `DirHandle` and produces a sorted list of plain files that aren't dotfiles (that is, their names don't begin with a "`.`"):

>     use DirHandle;

>     sub plainfiles {
>        my $dir = shift;
>        my $dh = DirHandle->new($dir)   or die "can't opendir $dir: $!";
>        return sort                       # sort pathnames
>               grep {    -f     }         # choose only "plain" files
>               map  { "$dir/$_" }         # create full paths
>               grep {  !/^\./   }         # filter out dot files
>               $dh->read( );             # read all entries
>     }

`DirHandle`'s `read` method behaves just like `readdir`, returning all remaining filenames. The bottom `grep` returns only those that don't begin with a period. The `map` turns the filenames returned by `read` into fully qualified filenames, and the top `grep` filters out directories, links, etc. The resulting list is then `sort` ed and returned.

In addition to `readdir`, there's also `rewinddir` (to move the directory handle back to the start of the filename list), `seekdir` (to move to a specific offset in the list), and `telldir` (to find out how far from the start of the list you are).

### 9.5.4. See Also

The `closedir`, `opendir`, `readdir`, `rewinddir`, `seekdir`, and `telldir` functions in perlfunc(1) and in Chapter 29 of Programming Perl; documentation for the standard DirHandle module (also in Chapter 32 of Programming Perl)

Copyright © 2003 O'Reilly & Associates. All rights reserved.