[Haskell-cafe] Automatic file closing after readFile

Matthew Brecknell haskell at brecknell.org
Thu Oct 18 06:58:45 EDT 2007


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!

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.



More information about the Haskell-Cafe mailing list