I am trying to read the contents of a file, turn the text to upper-case and then write it back.
Here is the code I had written:
import System.IO
import Data.Char
main = do
handle <- openFile "file.txt" ReadWriteMode
contents <- hGetContents handle
hClose handle
writeFile "file.txt" (map toUpper contents)
return ()
However, this writes nothing to the file, in fact, it even clears it.
I made some changes:
main = do
handle <- openFile "file.txt" ReadWriteMode
contents <- hGetContents handle
writeFile "file.txt" (map toUpper contents)
hClose handle
return ()
However, I get the error resource busy (file is locked)
. How can I get this working and why it didn't work in both cases?
Best Answer
Lazy IO is bad, and this is generally considered to be a pain point in Haskell. Basically the
contents
isn't evaluated until you go to write it back to disk, at which point it can't be evaluated because the file is already closed. You can fix this in several ways, without resorting to extra libraries you can use thereadFile
function and then check the length before writing back out:I would say this code is actually better anyway because you don't write back out to a file that is already empty, a pointless operation.
Another way would be to use a streaming library,
pipes
is a popular choice with some good tutorials and a solid mathematical foundation, and that would be my choice as well.