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

Hello perlmonks,
I am writing a program that checks a directory for FASTA (.fa) files (containing DNA sequences), opens them and prints out the names of the corresponding sequencing (characterised by '>' at the beginning of a line). However, my code cannot open the files and I don't know what the problem is.
Here's my code:

my $dir = "directory/"; opendir ( DH, $dir ) || die "Cannot open $dir: $!.\n"; foreach ( readdir DH) { if (/\.fa$/){ my $file = $_; open (READ, "$file") || die "Cannot open $file: $!.\n"; # her +e's the problem while (<READ>){ if ( /^>/){ print $_; } } } close (READ); } close (DH);

I could of course store each file name in a variable and open the files outside the loop, but I prefer a one-pass solution. Any ideas?

Replies are listed 'Best First'.
Re: Cannot open file within a loop
by huck (Prior) on Jun 14, 2017 at 07:07 UTC

    What directory is $file in? is it the same one that $dir is in?

    If you're planning to filetest the return values out of a readdir, you'd better prepend the directory in question. Otherwise, because we didn't chdir there, it would have been testing the wrong file.
    http://perldoc.perl.org/functions/readdir.html

      $file is in $dir
      but the error message spits out 'sequence.fa which is the correct name

        it is the correct name if you were in $dir, but you are not, you are in the directory that contains $dir arnt you?

        So from the directory containing dir, what is the correct name for the file

Re: Cannot open file within a loop
by Discipulus (Canon) on Jun 14, 2017 at 07:40 UTC
    Hello ic23oluk

    The current directory does not change when you open a folder handle, and I suspect that use warnings; must warn about this.

    Your open (READ, "$file") || die "Cannot open $file: $!.\n"; must be changed into open my $readfh,'<', $dir.'/'.$file or die "Cannot open $dir.'/'.$file: $!.\n";

    You can check if I'm right testing the file for existence just before trying to open it: warn "File [$file] not found" unless -e $file;

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Cannot open file within a loop
by Marshall (Canon) on Jun 15, 2017 at 01:07 UTC
    Some comments:
    • I prefer to almost always use a defined "my $variable" in a loop, especially when using nested loops each of which use $_. Doing otherwise can lead to problems. Using a "my" variable instead of $_ is very "cheap" execution time wise.
    • Normally assigning $_ to a variable is not needed. Do that as part of the loop setup.
    • In the "die" message, a trailing "\n" will suppress the Perl line number upon which the error occurred. For code like this, normally you will want a direct reference to the line number where the open failed, so don't put a trailing "\n". In some user programs, maybe the actual line number is confusing and you want a \n to suppress that. In any event, be aware of this difference.
    • Normally do not put a trailing "/" at the end of the directory name. This can at least confuse Windows on occasion. Prepend a "/" when expanding the path, "$dir/$sub_dir/$file".
    • Of course, readdir() returns just a name, not the full path, so that needs to be corrected in the open().
    • I think this should work, (untested):

      my $dir = "directory"; #### no trailing "/" opendir ( DH, $dir ) || die "Cannot open $dir: $!"; #### no "\n" foreach my $file ( readdir DH) # Note: only name, not full path { next unless $file =~ /\.fa$/; open (READ, '<', "$dir/$file") || die "Cannot open $dir/$file: $!"; + while (my $line =<READ>) { if ($line =~ /^>/) { print $line; } } close READ; } close (DH);