Directories
Instead of opendir and friends, in Perl 6 there is a single dir subroutine, returning a list of the files in a specified directory, defaulting to the current directory. A piece of code speaks a thousand words (some result lines are line-wrapped for better readability):
# in the Rakudo source directory
> dir
build parrot_install Makefile VERSION parrot docs Configure.pl
README dynext t src tools CREDITS LICENSE Test.pm
> dir 't'
00-parrot 02-embed spec harness 01-sanity pmc spectest.data
dir has also an optional named parameter test, used to grep the results
> dir 'src/core', test => any(/^C/, /^P/)
Parcel.pm Cool.pm Parameter.pm Code.pm Complex.pm
CallFrame.pm Positional.pm Capture.pm Pair.pm Cool-num.pm Callable.pm Cool-str.pm
Directories are created with mkdir, as in mkdir('foo')
Files
The easiest way to read a file in Perl 6 is using slurp. slurp returns the contents of a file, as a String,
> slurp 'VERSION'
2010.11
The good, old way of using filehandles is of course still available
> my $fh = open 'CREDITS'
IO()<0x1105a068>
> $fh.getc # reads a single character
=
> $fh.get # reads a single line
pod
> $fh.close; $fh = open 'new', :w # open for writing
IO()<0x10f3e704>
> $fh.print('foo')
Bool::True
> $fh.say('bar')
Bool::True
> $fh.close; say slurp('new')
foobar
File tests
Testing the existence and types of files is done with smartmatching (~~). Again, the code:
> 'LICENSE'.IO ~~ :e # does the file exist?
Bool::True
> 'LICENSE'.IO ~~ :d # is it a directory?
Bool::False
> 'LICENSE'.IO ~~ :f # a file then?
Bool::True
Easy peasy.
File::Find
When the standard features are not enough, modules come in handy. File::Find (available in the File::Tools package) traverses the directory tree looking for the files you need, and generates a lazy lists of the found ones. File::Find comes shipped with Rakudo Star, and can be easily installed with neutro if you have just a bare Rakudo.
Example usage? Sure. find(:dir<t/dir1>, :type<file>, :name(/foo/)) will generate a lazy list of files (and files only) in a directory named t/dir1 and with a name matching the regex /foo/. Notice how the elements of a list are not just plain strings: they’re objects which strinigify to the full path, but also provide accessors for the directory they’re in (dir) and the filename itself (name). For more info please refer to the documentation.
Useful idioms
- Creating a new file
-
open('new', :w).close - "Anonymous" filehandle
-
given open('foo', :w) { .say('Hello, world!'); .close }
December 3, 2010 at 9:25 am |
Reading the above, I think it’s nice that dir() by default skips “.” and “..”, because in Perl 5 I always do this: next if /^\.\.?$/;
December 3, 2010 at 9:27 am |
Right, you can tell it was specced (and implemented in Rakudo) by somebody who has written lots of Perl 5 code :-)
December 4, 2010 at 6:08 am |
You should use glob then
December 4, 2010 at 6:37 am |
I’m curious – why implement grep again as the “test” parameter? Does it do anything better?
December 4, 2010 at 8:55 am |
It excludes . and .. by default. Which means it saves you from writing a grep on your own in most use cases. Or put another way, it’s a convenience.
December 13, 2010 at 2:12 pm |
opendir/readder has a speed advantage in Perl 5 when there are many files/directories in a certain tree. Ie. the following code:
opendir D, ‘foo’;
while (my $file = readdir D) {
…
}
closedir D;
is faster and more memory efficient than the following (prettier looking) version:
for my $file () {
}
Is there some kind of mechanism (like lazy lists) in Perl 6 to have the implementation perform the optimal way?
December 13, 2010 at 2:13 pm |
ok, so the comment system ate my “less than” and “greater than” signs. I will replace them with [ and ]:
for my $file ([*]) {
…
}
December 13, 2010 at 2:25 pm |
Note that the speed disadvantage comes from doing all IO operations (and keeping the result in memory) before any processing can happen.
In Perl 6, this is not the case. The IO operations happen as the list items are accessed. If the list is not consumed, no internal calls to readline() will be made.
Lazy lists are good for something after all :-)
May 25, 2011 at 5:55 pm |
good tut!
thanks!