6.2 Directory Handles

6.2  Directory Handles

  In Perl, we can create a directory handle and read the list of files in a directory. A directory handle is just like a filehandle in many ways, but there are differences. To open a file, we use the open command with a filehandle argument.  To open a directory, we use the opendir command with a directory handle.  When we open a file with the open command, we can indicate whether we want to open the file for reading, writing, appending, and reading as well as writing, etc. However, with directory handles, we can only read
the names of files in the directory, we cannot write or append to a directory. This sounds quite logical. Just opening a directory does not accomplish anything unless we read the contents of the directory. readdir gives the list of files in a directory.  Once we have read a directory and obtained the file list, we can close the directory handle before we process the files. closedir is the command to close a directory handle.  The following program prints the names of the files in the current directory in a sorted order.

 Program 6.1

#!/usr/bin/perl

use strict;
opendir (THISDIR, ".");
my @files = readdir (THISDIR) or warn "Cannot open directory .; $!";
closedir THISDIR;

$" = "\n";
my @sortedFiles = sort @files;
print "@sortedFiles\n";

Unlike open used with filehandles, opendir requires a comma after the first argument. opendir is used only for opening a directory for reading the list of files. Opening a directory simply means that the program has access to the data structure stored by the operating system. Once we have read the list of files, we can close the directory handle if we are simply interested in getting the list of files. It is not necessary to keep the directory handle open unless we want to do further processing of the directory data
structure or node, as it is called.  It is customary to use all uppercase letters for the name of a directory handle although it not required. This is also the case with filehandles. In the Unix operating system, the current directory is known by the special name . and .. is the name of the parent directory. These two are printed as the contents of any directory. In the program given above, we open the current directory by using . to refer to it. Therefore, if we want to process the list of files obtained by reading a directory, we should remove these two files from the file list.

The output of the program given above looks like the following.

.
..
a
argv.pl
b
c
copy.pl
copy0.pl
copy1.pl
file-age.pl
file-read.pl
file-read1.pl
fileread.pl
include
junk
oldest.pl
printfile.pl
printfile1.pl
printfile2
printfile2.1
printfile2.2
read-file.pl
readdir.pl
readdir1.pl
readdirR.pl
readdirR0.pl
readdirR1.pl
readdirR2.pl
readdirR3.pl
readdirR4.pl
remove
size.pl
size1.pl
sizeR.pl
sizeR1.pl
tls
tls2

The following program also reads the names of files in a directory. It does so using a subroutine called readdirNR. The subroutine readdirR removes the two entries . and .. from the list of files it returns.

 Program 6.2

#!/usr/bin/perl

use strict;

sub readdirNR{
    my ($dir) = @_;
    opendir DIR, $dir;
    my @files = readdir DIR;
    closedir DIR;
    @files = grep {$_ !~ /^(\.|\.\.)$/} @files; 
    return @files;
}

my @files = readdirNR (".");

$" = "\n";
my @sortedFiles = reverse sort @files;
print "@sortedFiles\n";

The subroutine removes the two special file names using the line given below.

 

@files = grep {$_ !~ /^(\.|\.\.)$/} @files;

 

From the list of files @files, this statement greps or culls those lines that satisfy the condition given in the block of statements that grep takes as the first argument. The regular expression given inside the block checks to see if the file name does not literally match either . or .., and only if it does not match, it keeps the name of the file. Therefore,
@files
after the grep statement is executed has all but the two special files. The pattern given above could also have been written as the following.

 

/^[.]{1,2}$/