[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