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

Hi,

I want to read in the entire contents of an mbox file and then clear it immediately after. Considering this is an mbox file, I have to lock it in case new mail comes in. I can't work out the most efficient way to clear the file after reading, without closing it and losing the lock, then opening it again with '>'. If mail arrives in while doing that I've lost it.

Any suggestions?

  • Comment on Read entire file then clear while flocking

Replies are listed 'Best First'.
Re: Read entire file then clear while flocking
by roboticus (Chancellor) on Nov 04, 2011 at 22:50 UTC

    citycrew:

    Can you simply rename it so the mailer can start a new one, and let you process the other one without worrying about locking or hurrying? I don't whack EMail in perl, so there may be some shortcomings to this approach that I haven't thought of.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      Hi Roboticus,

      My fear with doing that was that if mail was being written to the spool file when I try to rename it, it will lose that email. If, however, mv recognizes a locked file then I am golden. Would you happen to know if it does?

        citycrew:

        Sorry, I don't know that. If it's a unix box, though, renaming it won't affect the processes that have it open. So you could potentially rename it and wait a while (giving other jobs a chance to finish using it) and *then* process it. Hopefully someone a bit more knowledgeable about the Unix filesystem will chime in. I'm even less knowledgeable about windows filesystems (except for FAT12/16, yech!)...

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.

Re: Read entire file then clear while flocking
by BrowserUk (Patriarch) on Nov 05, 2011 at 00:10 UTC

    This sequence seems to work for me:

    open my $fh, '+<', $theFile or die $!; my $stuff = do{ local $/; <$fh> }; truncate $fh, 0; close $fh;

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Read entire file then clear while flocking
by JavaFan (Canon) on Nov 05, 2011 at 00:14 UTC
    I think you want truncate, as in the untested code below:
    use autodie; use Fcntl ':flock', ':seek'; open my $fh, "+<", "mail"; flock $fh, LOCK_EX; my $text = do {local $/; <$fh>}; seek $fh, SEEK_SET, 0; # Only needed if you're going to write. truncate $fh, 0; close $fh;
      POSITION and WHENCE reversed - it ought to be: seek $fh, 0, SEEK_SET;
Re: Read entire file then clear while flocking
by Kc12349 (Monk) on Nov 04, 2011 at 22:54 UTC

    You could take a look at File::Slurp's edit_file sub. This allows you to edit file contents. You could push the contents from $_ to another variable and then clear $_. I'm not sure how locks are done internally though.

    use File::Slurp qw(edit_file); my $contents = ''; edit_file { $contents = $_; $_ = '';} 'temp/test.txt'; print $contents;
Re: Read entire file then clear while flocking
by citycrew (Acolyte) on Nov 05, 2011 at 05:09 UTC

    Thanks guys, I'll check out the truncate code and see if it works for me