Files and Directories Handling in Perl
Perl has strong support for handling files and directories, which are the bread-and-butter of dealing with the disk and the filesystem. Many modules on CPAN (= the Comprehensive Perl Archive Network) aim to facilitate the task even further.
Table of Contents
The Basics
For the basics, read about the open function (on perlopentut or on recommended books or tutorials) as well as other built-ins such as opendir, readdir, closedir, mkdir. There are also many UNIX-oriented file-system-builtins listed on perlfunc which may prove of utility.
Modules
Useful modules for files and directories handling are:
- File::Spec - a core module to handle file and directory paths portably.
- File::Basename - a core module to portably extract the basename, the dirname, the suffix and other file paths parsing.
- String-ShellQuote - quote strings for passing through the shell. Also see the list forms of system.
- File::Path - a core module to create or remove directory trees (portably).
- File::Copy - a core module to copy files.
- IO-All - an all-in-one IO package with a lot of syntactic sugar. Non-core.
- File-Slurp - a module for fast and easy input and output from files and directories. The interface is procedural and quite Spartan, but is still useful.
Directory Traversal
The built-in module for traversing a directory tree in Perl is File::Find, but it has some severe limitations in interface and use. Some better alternatives are:
-
File-Find-Object - an object-oriented replacement for File::Find that: 1) can be instantiated 2) has an iterative interface 3) can be interrupted in the middle and 4) can return result objects instead of path names.
-
File-Next - an alternative with an iterative interface, but incapable of being instantiated.
-
File-Find-Rule, which is still based on File::Find, and File-Find-Object-Rule provide a more convenient and succinct interface for finding what you want.
-
Path-Class-Rule, provides an object oriented and iterative file finder using Path::Class. Also of interest is its “See Also” section, which contains links to other implementations, and a comparison of them.
Examples
These are a set of examples for manipulating files and directories using Perl. Each will be shown in several versions including ones using IO-All, ones using core modules, and if relevant ones from the command line.
Copying a file
#!/usr/bin/perl use strict; use warnings; use IO::All; my ($source_filename, $dest_filename) = @_; io->file($source_filename) > io->file($dest_filename);
#!/usr/bin/perl use strict; use warnings; use File::Copy qw(copy); my ($source_filename, $dest_filename) = @_; copy($source_filename, $dest_filename);
Overwriting a file with text
#!/usr/bin/perl use strict; use warnings; use IO::All; io->file("output.txt")->utf8->print("Hello World!\n");
#!/usr/bin/perl use strict; use warnings; use autodie; open my $out, '>:encoding(utf8)', "output.txt"; print {$out} "Hello World!\n"; close($out);
Processing the Lines of a File
#!/usr/bin/perl use strict; use warnings; use File::Slurp; my @filenames = @ARGV; foreach my $fn (@filenames) { edit_file_lines sub { s/\bFrom\b/To/g }, $fn; }
#!/usr/bin/perl use strict; use warnings; use autodie; use File::Temp ( qw(tempfile) ); my @filenames = @ARGV; foreach my $fn (@filenames) { open my $in, '<', $fn; my ($tempout, $temp_fn) = tempfile(); while (my $line = <$in>) { chomp($line); # Perform the operation here. $line =~ s/\bFrom\b/To/g; print {$tempout} "$new_line\n"; } close($in); close($tempout); rename($temp_fn, $fn); }
$ perl -i.bak -lp -e 's/\bFrom\b/To/g' *.txt
Reading an entire UTF-8 file into a big variable
#!/usr/bin/perl use strict; use warnings; use IO::All; my $string = io->file($my_filepath)->utf8->slurp;
#!/usr/bin/perl use strict; use warnings; use autodie; sub _utf8_slurp { my $filename = shift; open my $in, '<:encoding(utf8)', $filename; local $/; my $contents = <$in>; close($in); return $contents; } my $file_contents = _utf8_slurp($my_filepath);
$ perl -i.bak -ln -0777 -C -ln -e 'Something with $_ here' "$my_utf8_filepath"
Appending to a File
#!/usr/bin/perl use strict; use warnings; use IO::All; my $string_to_append = "My new line\n"; $string_to_append >> io->file($my_file_path);
#!/usr/bin/perl use strict; use warnings; use autodie; my $string_to_append = "My new line\n"; { open my $out, '>>', $my_file_path; print {$out} $string_to_append; close($out); }
Line count
#!/usr/bin/perl use strict; use warnings; use IO::All; sub count_lines { my ($filename) = @_; my $fh = io->file($filename); my $count = 0; while (my $l = <$fh>) { $count++; } return $count; }
#!/usr/bin/perl use strict; use warnings; use autodie; sub count_lines { my ($filename) = @_; open my $fh, '<', $filename; my $count = 0; while (my $l = <$fh>) { $count++; } close($fh); return $count; }
$ perl -lnE 'END{say "$ARGV has $. lines";}' /path/to/myfile.txt
Deleting a directory tree
#!/usr/bin/perl use strict; use warnings; use IO::All; io("./path-to-subdir")->rmtree();
#!/usr/bin/perl use strict; use warnings; use File::Path qw(rmtree); rmtree(["./path-to-subdir"], 1, 1);
Prepending to a File (While Slurping)
#!/usr/bin/perl use strict; use warnings; use IO::All; my $filename = 'foo.txt'; my $text_to_prepend = "[Text to Prepend]\n"; my $fh = io->file($filename); $fh->print( $text_to_prepend . $fh->slurp() );
#!/usr/bin/perl use strict; use warnings; my $filename = 'foo.txt'; my $text_to_prepend = "[Text to Prepend]\n"; open my $in_fh, '<', $filename or die "Could not open file '$filename' for reading! - $!"; my $contents = do { local $/; <$in_fh>;}; close($in_fh); open my $out_fh, '>', $filename or die "Could not open file '$filename' for writing! - $!"; print {$out_fh} $text_to_prepend . $contents; close($out_fh);
