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

Hi all ! In one hand,i would thanks guys who answered me yesterday and in other hand my problem is :-)

i want manipulate files but in first time i want catch
them in a list for treat them after..
my code is:

@listDir = readdir(ORIG); if (!@listDir) { die("there no files !") ; } foreach $i (@listDir) { if ( -f $i) { print "$i is a file !"; push(@filesInDir,$i); } else {print "$i isn't a file !\n"; } }
but for example i place a file "hello.exe" in
this directory and the program print "hello.exe isn't a file"
i have taste another code like this:
$i = 'C:/test/hello.exe' ; if ( -f $i) { print "$i is a file !"; push(@filesInDir,$i); } else {print "$i isn't a file !\n"; } }
And miracle(it's a joke sure !) the program print
"hello.exe is a file" ,but i don't want take by my hands all file in this directory
thanks for answer me !
that many ways to do it (sic !)

Replies are listed 'Best First'.
Re: file's treatment
by Corion (Patriarch) on Apr 11, 2004 at 18:05 UTC

    In almost all such cases, the cause is that the "current directory" and the "path to your file" together do not work out to an existing file anymore. readdir returns you only the file names, and not the directory name.

    I suggest that you add the directory to the file names as well, so you don't get confused as which files comes from where:

    use File::Spec; my $dir = 'c:/test/'; opendir ORIG, $dir or die "Couldn't read '$dir': $!"; my @listDir = map { File::Spec->catfile( $dir, $_ )} readdir(ORIG); closedir ORIG; print $_ for @listDir;
Re: file's treatment
by matija (Priest) on Apr 11, 2004 at 18:08 UTC
    The difference is that in the first case $i only contains the filename, but in the second case it contains the full path.

    If you had been in the test directory, the first version would work, too.

    Try changing the test in the first version to -f "$ORIG/$i" (yes, the / should work on Windows, too).

Re: file's treatment
by runrig (Abbot) on Apr 11, 2004 at 18:09 UTC
    Are you reading the files from the current directory? If you print $i, is there an absolute path to the file as in your last example? If it's a relative path (or just the file name), maybe you need to chdir to the appropriate directory first, or prepend the correct path to the file name.
Re: file's treatment
by tilly (Archbishop) on Apr 11, 2004 at 19:58 UTC
    Advice not related to your question.

    Glancing at your code, you are clearly not using strict.pm. It is generally a good idea to use that, and then declare all of your variables with my or use vars.

    The biggest single win that you'll get is that for a small amount of extra declarations, you will catch many typos because Perl will notice that variables are undeclared. (Much better than just having your program silently misbehave for difficult to track down reasons.)

Re: file's treatment
by graff (Chancellor) on Apr 11, 2004 at 20:49 UTC
    As others have said, the problem is that "readdir()" returns file names, and the "-f" test needs the path of the directory being read to be attached to each file name, in order to find each file.

    One other point: you could do what you want in a single pass, using "grep":

    my $path = "C:/some/path"; opendir( ORIG, $path ) or die "opendir failed on $path: $!"; my @filesInDir = grep { -f "$path/$_" } readdir( ORIG ); closedir ORIG;
    How easy is that? If you really want to list all the files and non-files to STDOUT while you're reading the directory (which you'll probably get tired of quickly), here's what I would put in place of that single grep line:
    while ( my $file = readdir( ORIG )) { my $verb = "isn't"; if ( -f "$path/$file" ) { push @filesInDir, "$path/$file"; $verb = "is"; } print "$path/$file $verb a file\n"; }
    Personally, I like the shorter version better.