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

Dear all,

I have a follow up question to an answer I received from a previous question, which you can see here.

This is a little bit unusual. My program generates all the combinations of the four DNA bases via the subroutine and saves them to disk. It later calls the file and reads through it one line at a time with a while loop. With larger sets of combinations, 5 or more bases long, this works fine but with a smaller sets, 3 or 4 bases I encounter a strange error. After running the sub routine the program reopens the file but the file is empty so the program skips the while loop (the file is empty)then quits. Opening the resulting output of the combination sub routine shows that all the combinations are indeed there. The file size for 3 base long combinitaions is just 320 bytes.
I have followed this in a debugger and its reproducible. My guess is that the contents of the file are not been flushed to disk until the program ends. This happens on both Linux and Win2k. I am also having problems deleting the file after use. I've never run into this problem before. Ideas anyone?

Here is a script that illustrates the problem.
Try varying the commentating on the two unlink lines to see different effects and the changing the length of the sequence that is generated

#!/usr/local/bin/perl -w $| = 1; #generate promoters my $Bases = "ACGT"; #my @PromoterLenghts = ($PromoterMinLenght...$PromoterMaxLength); my @PromoterLenghts = (4); my $PromotroListLength = $#PromoterLenghts; $PromotroListLength ++; #unlink 'permute.txt'; my ($currLenght, $permutelist_filename); foreach $currLenght (@PromoterLenghts){ $permutelist_filename = &permute_bases ($currLenght, $Bases); } #print "Sequences file $permutelist_filename\n"; open (PIN, "permute.txt")||die "Can't open file: $!\n"; open (OUTPUT, ">output.txt")||die "Can't open file: $!\n"; while (<PIN>){ $promoter = $_; chomp $promoter; #do intrestering stuff with promoter sequence print OUTPUT "$promoter\n"; } close PIN ||die "Could not close sequences file: $!"; close OUTPUT ||die "Could not close output file: $!"; unlink 'permute.txt'; ###################################################################### +### sub permute_bases { my( $length, $bases )= @_; my @bases= split //, $bases; my @digit= (0) x $length; my $seq= $bases[0] x $length; my $permutelist_filename = "permute.txt"; open (PERMUTEOUT, ">>$permutelist_filename"); while( 1 ) { print PERMUTEOUT $seq,$/; print $seq,$/; my $pos= 0; while( @bases <= ++$digit[$pos] ) { substr( $seq, $pos, 1 )= $bases[ $digit[$pos]= 0 ]; return if $length <= ++$pos; } substr( $seq, $pos, 1 )= $bases[ $digit[$pos] ]; } close PERMUTEOUT ||die "Could not close $permutelist_filename: $!" +; return ($permutelist_filename); }
  • Comment on Program can not read the contents of a small file that it has recently written!
  • Download Code

Replies are listed 'Best First'.
Re: Program can not read the contents of a small file that it has recently written!
by Abigail (Deacon) on Jun 26, 2001 at 03:30 UTC
    The problem is the return statement in the while in the subroutine permute_bases. If you return here, the file is not closed and hence buffers are not flushed. If you then open the file and read from it, there is no garantee that what you wrote is already there. (Also note that the open in the subroutine has an unchecked return value - if the open fails, nothing would be written to the file either, but that's probably not the case).

    If you would use an autovivified filehandle, using a lexical scalar, then the file would be closed if you perform the return - the filehandle goes out of scope, closing the file.

    -- Abigail

Re: Program can not read the contents of a small file that it has recently written!
by lemming (Priest) on Jun 26, 2001 at 02:42 UTC

    For one thing, you're having precedence problems.
    Either do

    close FILE or die "die die";
    or
    close(FILE) || die "die die"; Oh, and spell your variables, "Lenght" had me chasing possible typo problems

    Update: There's more to be done, but I'm not sure I have the strength

    Real Update: You have a return in your subroutine while loop.
    return if $length <= ++$pos;
    so you never get to your close which is outside an infinite loop.

      Ah yes, that's it.
      Related to the fact that I didn't fully understand the code I used from the last question, I've gone bright red :-/
      Change the line return if $length <= ++$pos; to the lines
      if ($length <= ++$pos){ close (PERMUTEOUT) ||die "Could not close $permutelist_filename: $ +!"; return ($permutelist_filename); }

      And it all works as expected. My apologies for wasting your time on this one and thanks to all of you for your help.
Re: Program can not read the contents of a small file that it has recently written!
by davorg (Chancellor) on Jun 26, 2001 at 12:13 UTC
Re: Program can not read the contents of a small file that it has recently written!
by nysus (Parson) on Jun 26, 2001 at 02:45 UTC
    I didn't step through the logic of the whole program but this looks rather suspect:
    my @PromoterLenghts = (4); my $PromotroListLength = $#PromoterLenghts;
    It looks like you want to set the first array to have four empty elements. What you are actually doing is setting the array to have its first element equal "4".

    $PM = "Perl Monk's";
    $MCF = "Most Clueless Friar Abbot";
    $nysus = $PM . $MCF;

      I really do want an array of one value, a 4 in this case. My original line was my @PromoterLenghts = ($PromoterMinLength .. $PromoterMaxLength); the min and max values were user entered.
      Its most likely that I have made some kind of stupid mistake/typo in the code but I can't see what it is.
      Try setting the @PromoterLenghts array to (2,3) and see what happens. Oh and delete any old permute.txt or output files that were generated on previous runs first.
Re: Program can not read the contents of a small file that it has recently written!
by nysus (Parson) on Jun 26, 2001 at 02:33 UTC
    Let me be the first to tell you: throw a use strict line near the top of your code.

    $PM = "Perl Monk's";
    $MCF = "Most Clueless Friar Abbot";
    $nysus = $PM . $MCF;

      Let me be the first to tell you: throw a use strict line near the top of your code.

      I'm sorry, but I don't get it. How does adding a use strict; help in solving the problem?

      -- Abigail

      Sorry the original code does have a use strict in it.
      As you can see almost all the virabels are defined with my.
      So add a my to the first line were the variable $prometer is used along with use strict; at the top and we still have the same problem.