[Haskell-cafe] Automatic file closing after readFile

Magnus Therning magnus at therning.org
Thu Oct 18 08:16:37 EDT 2007


On Thu, Oct 18, 2007 at 20:58:45 +1000, Matthew Brecknell wrote:
>Magnus Therning:
>>     hasEmpty s = let
>>             _first_empty = s !! 0 == '\n'
>>             _last_empty = (reverse s) !! 1 == '\n'
>>         in _first_empty || _last_empty
>> 
>>     loadAndCheck fp = liftM hasEmpty $ readFile fp
>> 
>>     main = getArgs >>= filterM loadAndCheck >>= mapM_ putStrLn
>> The one problem I had was that running this on /all/ files in my WP
>> resulted in an exception:
>> 
>>     *** Exception: ./wp-includes/images/smilies/icon_mrgreen.gif:
>>     openFile: resource exhausted (Too many open files)
>> 
>> Is there some (easy) way to avoid this while still using readFile?
>
>The perils of lazy IO: readFile closes its file descriptor only if it
>is is forced to read to end of file. Otherwise, you rely on the garbage
>collector to run the finaliser on the file handle sometime after it
>becomes unreachable, but since file handle exhaustion does not trigger
>garbage collection, there are no guarantees. See also the System.IO
>documentation.
>
>For an extremely hackish (and untested) solution to your problem,
>replace the expression (_first_empty || _last_empty) with (_last_empty
>|| _first_empty). If you can explain why that works, then you advance
>to the next level in your training!

I can see how that could have worked.  Lazy thinking indeed :-)  I
wonder if the fact that it doesn't work should be considered a bug?

Just to make sure I changed (broke) my code so that the very last
character would be read (in case there is an almost crazy level of
optimisation in ghc):

             _last_empty = (reverse s) !! 0 == '\n'

Still no cigar :(

>For a less hackish solution, you need to do a bit more work. Again, this
>is untested.
>
>> loadAndCheck fn = bracket (openFile fn ReadMode) hClose checkContents
>> checkContents fh = do { s <- hGetContents fh; return $! hasEmpty s }
>
>Note the explicit close, and "return $!" to ensure that hasEmpty has
>done its work before the file is closed.

Ah, `bracket` is a handy function to know!

And it does work!

/M

-- 
Magnus Therning                             (OpenPGP: 0xAB4DFBA4)
magnus@therning.org             Jabber: magnus.therning@gmail.com
http://therning.org/magnus
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://www.haskell.org/pipermail/haskell-cafe/attachments/20071018/3308083a/attachment.bin


More information about the Haskell-Cafe mailing list