oblate kramrdc has asked for the wisdom of the Perl Monks concerning the following question:

Hi Fellow monks!

I use chomp($TARGETFILE=<STDIN>) to read from a file.

Is there a way to tell your program to read all the files listed in a specific directory.

So that the user won't need to enter the filename one by one.

Thanks in advance!!!

Replies are listed 'Best First'.
Re: Read from directory list...
by kyle (Abbot) on Feb 06, 2007 at 17:57 UTC

    You should have a look at opendir and readdir. I frequently have code that looks like:

    opendir DIRHANDLE, 'directory-name' or die "Can't opendir: $!"; my @plain_files = grep( !/^\./ && -f, readdir( DIRHANDLE ) ); closedir( DIRHANDLE );

    I find it really handy to use grep to pick out the things I want and go from there. If you want to recurse into sub directories and/or do other fancy stuff, have a look at File::Find.

      Thanks a lot!
Re: Read from directory list...
by tirwhan (Abbot) on Feb 06, 2007 at 17:58 UTC

    This is an FAQ


    All dogma is stupid.
Re: Read from directory list...
by varian (Chaplain) on Feb 06, 2007 at 18:15 UTC
    Use globbing to obtain a subset of the directory, then collect the content in a list.
    #!/usr/bin/perl -w my @files = <*.pl>; # get list of .pl files in this dir my @content; foreach my $file (@files) { if (-f $file && open(FH,"<","$file")) { @content= (@content, <FH>); # add filecontent close(FH); } } # optionally: chomp @content print "$_" foreach @content;
      When you add each file's lines to @content you are copying the entire array every time around the loop. This could quickly get expensive. It would probably be better to push onto the array, so instead of

      @content= (@content, <FH>);

      you could do

      push @content, <FH>;

      I ran a benchmark of these two methods on a sample of 65 scripts totalling 2082 lines, "Copy" being your original and "Push" my suggested alternative. Here's the benchmark code

      and here's the result

      Rate Copy Push Copy 2.32/s -- -94% Push 41.9/s 1710% --

      As you can see, copying the array each time takes a lot of resources.

      Cheers,

      JohnGG

Re: Read from directory list...
by swampyankee (Parson) on Feb 06, 2007 at 19:02 UTC

    Most of the time, I tend to prefer glob to opendir followed by readdir, but that's mostly stylistic.

    For glob, you would do something vaguely like:

    my @list = glob('*');

    I believe glob ignores hidden files (on *ix, files with names starting with "."), while readdir doesn't. With readdir, you'll always get at least two files, as . (the directory itself) and .. (its parent) will (almost) always show up (offhand, I don't know if .. will show up for the root directory on *ix), so you'll have to handle these if you're going to recurse through a directory tree, a la find.

    emc

    Insisting on perfect safety is for people who don't have the balls to live in the real world.

    —Mary Shafer, NASA Dryden Flight Research Center
      > I believe glob ignores hidden files (on *ix, files with names starting with "."),
      > while readdir doesn't.

      It depends on how you call glob:
      In a directory containing the files aaaa, bbbb, cccc, .dddd, .eeee, .ffff

      glob (and similar '<>'):
      $ perl -e "print '-> ', join '|', glob('*');" -> aaaa|bbbb|cccc $ perl -e "print '-> ', join '|', glob('.*');" -> .|..|.dddd|.eeee|.ffff $ perl -e "print '-> ', join '|', glob('* .*');" -> aaaa|bbbb|cccc|.|..|.dddd|.eeee|.ffff
      readdir:
      $ perl -e "opendir DIR, '.'; print '->', join '|', readdir(DIR);" ->.|..|aaaa|bbbb|cccc|.dddd|.eeee|.ffff

      klekker