6.11.6 Portability in File Names: Module

6.11.6  Portability in File Names: Module File::Spec::Functions

     File names are written in different ways in different operating systems. For example, in Unix and variations of it such as Linux and Mac OS X or Mac OS X Server, the root directory is named /, whereas in Windows the root directory starts with the name of a drive such as C:\. In Mac OS prior to OS X, a full pathname starts with the name of the volume or disk without any prefix. So, if there is a disk or volume called Macintosh HD, a fully qualified name starts with the name Macintosh HD:. The directory separator in Unix is /; it is \ in Windows and : in Mac OS 9 or lower. Therefore, if we want to write programs that deal with files and directories and want these programs to work without much modification across
operating systems, we need to exercise care right from the beginning.

Perl provides a set of modules under the File::Spec class that deal with names of files and directories in a general way. The module called File::Spec is object-oriented and provides several methods to manipulate file and directory names. There are also several subclasses such as File::Spec::Unix, File::Spec::Mac, File::Spec::Win32 and File::Spec::OS2 that
provide operating system specific functionalities. There is an additional module called File::Spec::Functions that allows one to use the methods defined in File::Spec as functions. We discuss the last module in this section.

The File::Spec module loads the appropriate module for the current operating system. The

File::Spec::Functions module is a subclass of File::Spec and hence works with the current operating system. Among the functions available in the File::Spec::Functions module are functions for finding the name of the root directory appropriate for the operating system, concatenating names of directories, concatenating names of a sequence of directories with that of a file name, and to find out if the name of a file is absolute or not.

The following program uses a selection of functions in the File::Spec::Functions module.

 Program 6.26

#!/usr/bin/perl
#fileSpec.pl

use strict;
use File::Spec::Functions qw(:ALL);
$" = "\n\t";

print "The Operating System is " . $^O . "\n";
print "The root directory is " . File::Spec::Functions::rootdir () . "\n";
my $curdir = File::Spec::Functions::curdir ();
print "The current directory is " . $curdir . "\n";
print "The current absolutized directory is " .absolutize ($curdir) ."\n";
print "The up directory is " . File::Spec::Functions::updir () . "\n";
my @path = File::Spec::Functions::path (); 
print "The PATH environment variable contains\n\t@path\n"; 

my $dir1 = File::Spec::Functions::rootdir() .
           File::Spec::Functions::catdir ("home", "kalita", "perl");
print "The directory is $dir1\n";
my $dir2 = File::Spec::Functions::catdir ("kalita", "perl");
print "The directory is $dir2\n";
my $file1 = File::Spec::Functions::catfile (
                    File::Spec::Functions::catdir ("kalita", "perl"), 
                    "mkdir.pl");
print "The file is $file1\n";

opendir (DIR, "$curdir") or 
          die "Cannot open directory: $!";
my @files = readdir DIR or die "Cannot open directory: $!";
@files = File::Spec::Functions::no_upwards (@files);
printf "\n%-20s %-20s %-30s\n", "Original Name", "Absolute", "Relative";
print "-" x 55, "\n";
foreach (@files){
  printf "%-20s %-20s %-30s\n", "$_", &relativize($_),  &absolutize($_);
}

#absolutize a file name 
sub absolutize{
  my ($file) = @_;
  return $file if (File::Spec::Functions::file_name_is_absolute ($file));
  return File::Spec::Functions::rel2abs ($file);
}
#relativize a file name
sub relativize{
   my ($file) = @_;
   return $file unless (File::Spec::Functions::file_name_is_absolute ($file));
   return File::Spec::Functions::abs2rel ($file);
}

When we use the File::Spec::Functions module a few of the subroutine names are imported automatically, but a few are not. That is why, we use the :ALL keyword in the use statement. What is imported automatically from a module and what needs to be explicitly imported is a choice the authors of the modules make. To import only a few of the optional ones, their names can be directly specified in the use statement. To find out what needs to be imported explicitly, one must
read the documentation for the module.

The program first prints the name of the current operating system by looking at the special variable $^O. It then prints the representation used by the operating system for the current directory and the directory one level above the current directory. In Unix, these simply are the two dot files. The program next prints the PATH environment variable using the path function.

The module File::Spec::Functions provides a function called rootdir to obtain the root directory in the operating system. It has a function called catdir to concatenate a sequence of directory names, and a function called catfile to take one or more directory names and a file name and make a complete path.

The program next opens the current directory. It uses the no_upwards function to remove the two dotfiles. This is handy. Otherwise, we have to remove these dotfiles on our own, as we have done in most of our programs dealing with directories so far. The program goes through a loop and prints the name of each file in the current directory both as a relative and an absolute name.

There are two simple subroutines that absolutize and relativize a file or directory name. These two subroutines use the method file_name_is_absolute to do so. The absolutize function calls the function rel2abs to make a file or directory name absolute. The relativize function uses the abs2rel to make the file names relative. These two functions: abs2rel and rel2abs are not automatically exported by the File::Spec::Functions module. To import these two functions, we had used the :ALL keyword with the use statement. There are other functions, not discussed here that also need to be imported explicitly.

A output of running this program on a Linux machine is given below.

The Operating System is linux
The root directory is /
The current directory is .
The current absolutized directory is /home/kalita/perl/file
The up directory is ..
The PATH environment variable contains
        .
        /home/kalita/bin
        /bin
        /usr/bin
        /usr/local/bin
        /usr/sbin
        /usr/bin/X11
        /usr/bin/mh
The directory is /home/kalita/perl
The directory is kalita/perl
The file is kalita/perl/mkdir.pl

Original Name        Absolute             Relative
-------------------------------------------------------
jk1.jpg              jk1.jpg              /home/kalita/perl/file/jk1.jpg
dircopytest.pl       dircopytest.pl       /home/kalita/perl/file/dircopytest.pl
mkdir1.pl            mkdir1.pl            /home/kalita/perl/file/mkdir1.pl
checkPath.plx        checkPath.plx        /home/kalita/perl/file/checkPath.plx
filecopy.pl          filecopy.pl          /home/kalita/perl/file/filecopy.pl
mkdir.pl             mkdir.pl             /home/kalita/perl/file/mkdir.pl
ncopy.pl             ncopy.pl             /home/kalita/perl/file/ncopy.pl
basename.pl          basename.pl          /home/kalita/perl/file/basename.pl
FileR.pm             FileR.pm             /home/kalita/perl/file/FileR.pm
fileparse.pl         fileparse.pl         /home/kalita/perl/file/fileparse.pl
a                    a                    /home/kalita/perl/file/a
myMakePath.pl        myMakePath.pl        /home/kalita/perl/file/myMakePath.pl
myMkpath.pl          myMkpath.pl          /home/kalita/perl/file/myMkpath.pl
aa                   aa                   /home/kalita/perl/file/aa
myMkpath1.pl         myMkpath1.pl         /home/kalita/perl/file/myMkpath1.pl
fileFuns.pl          fileFuns.pl          /home/kalita/perl/file/fileFuns.pl
rmtree.pl            rmtree.pl            /home/kalita/perl/file/rmtree.pl
fileSpec.pl          fileSpec.pl          /home/kalita/perl/file/fileSpec.pl

A part of the output of running this program on an Macintosh machine with OS X Server is given below.

The Operating System is rhapsody
The root directory is /
The current directory is .
The current absolutized directory is /Local/Users/kalita/perl/file
The up directory is ..
The PATH environment variable contains
        /Local/Users/kalita/bin/powerpc-apple-rhapsody
        /Local/Users/kalita/bin
        /usr/local/bin
        /usr/bin
        /bin
        /usr/sbin
        /sbin
The directory is /home/kalita/perl
The directory is kalita/perl
The file is kalita/perl/mkdir.pl

Original Name        Absolute             Relative
-------------------------------------------------------
FileR.pm             FileR.pm             /Local/Users/kalita/perl/file/FileR.pm
basename.pl          basename.pl          /Local/Users/kalita/perl/file/basename
.pl