My first impression of readFile
was of a tradeoff between its convenience and the possibility of it leaving file descriptors open longer than needed, with no way to close them. As an experiment I tried the following (highly practical) program, thinking it might choke by trying to maintain a thousand open file descriptors:
main = do
mapM_ (\idx -> readIt) [1..1000]
where readIt = do
contents <- readFile "/etc/passwd"
putChar $ head contents
But it actually does a pretty good job of reclaiming file descriptors; the count never gets above around 70:
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 4
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 5
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 6
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 7
...
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 65
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 66
close(3) = 0
close(4) = 0
close(5) = 0
...
close(54) = 0
close(55) = 0
close(56) = 0
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 3
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 4
How is this happening? Is it just that the values of contents
are getting GC'd, and with them the no-longer-referenced file descriptors? Or is there some separate mechanism for managing file descriptor resources? Whatever the mechanism is, it seems to be working pretty well - how can you know when it's best to use hClose
explicitly?
Because files are limited resources managed by the operating system, making sure files are closed after use will protect against hard-to-debug issues like running out of file handles or experiencing corrupted data.
Though Python automatically closes a file if the reference object of the file is allocated to another file, it is a standard practice to close an opened file as a closed file reduces the risk of being unwarrantedly modified or read.
The act of closing the file (actually, the stream) ends the association; the transaction with the file system is terminated, and input/output may no longer be performed on the stream. The stream function close may be used to close a file; the functions described below may be used to open them.
A file needs to be closed after a read or write operation to release the memory allocated by the program. In C, a file is closed using the fclose() function. This returns 0 on success and EOF in the case of a failure. An EOF is defined in the library called stdio.
It is better to explicitly close resources yourself, only when you have some low level resource constraint that you can actually enforce manually.
The cases to consider:
finally
or bracket
)The Haddock docs for System.IO
have this to say:
GHC note: a Handle will be automatically closed when the garbage collector detects that it has become unreferenced by the program. However, relying on this behaviour is not generally recommended: the garbage collector is unpredictable. If possible, use an explicit hClose to close Handles when they are no longer required. GHC does not currently attempt to free up file descriptors when they have run out, it is your responsibility to ensure that this doesn't happen.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With