The function below always returns "", rather than the file's contents.
_Real World Haskell_ touches on how laziness can make this problimatic,
without really giving a solution, other than throwing in a putStr to
force evaluation, which can't be done here. How can I make hGetContents
strict, to ensure the file contents are really read before it gets closed?
readFile' file = do
f <- openFile file ReadMode
-- locking will go here
s <- hGetContents f
hClose f
return s
Haskell won't actually read the file unless you need the contents of
the file. In order to ensure that the file contents are read before
it gets close, you need to actually perform an operation that will
force evaluation of the file. Haskell will read the file then to
perform whatever operation you specify.
Also, I noticed that opening a file and locking it involves a
very verbose seeming dance. (It's 2 lines of code in most other languages.)
Does this indicate that few people bother with file locking in Haskell
and so it still has these rough edges, or that there's a better way to do
it that I have not found yet?
openLocked file = do
handle <- openFile file ReadMode
lockfd <- handleToFd handle -- closes handle
waitToSetLock lockfd (ReadLock, AbsoluteSeek, 0, 0)
handle' <- fdToHandle lockfd
return handle'
You should go to haskell.org/hoogle, and search openFile, or check
out the Haskell98 report, but I'm under the impression that ghc
locks the file for you when you open the file.:Implementations should enforce as far as possible, at least locally to the Haskell process, multiple-reader single-writer locking on files. That is, there may either be many handles on the same file which manage input, or just one handle on the file which manages output. If any open or semi-closed handle is managing a file for output, no new handle can be allocated for that file. If any open or semi-closed handle is managing a file for input, new handles can only be allocated if they do not manage output. Whether two files are the same is implementation-dependent, but they should normally be the same if they have the same absolute path name and neither has been renamed, for example.
Error reporting: the openFile computation may fail with isAlreadyInUseError if the file is already open and cannot be reopened; isDoesNotExistError if the file does not exist; orisPermissionError if the user does not have permission to open the file