Comme d'autres l'ont dit, c'est en raison de l'évaluation différée. La poignée est à moitié fermé après cette opération, et se ferme automatiquement une fois toutes les données sont lues. Les deux hGetContents et readFile sont paresseux de cette façon. Dans le cas où vous rencontrez des problèmes avec poignées ouvertes, généralement vous venez de force de la lire. Voici le moyen le plus facile:
import Control.Parallel.Strategies (rnf)
-- rnf means "reduce to normal form"
main = do inFile <- openFile "foo"
contents <- hGetContents inFile
rnf contents `seq` hClose inFile -- force the whole file to be read, then close
putStr contents
Ces jours-ci, cependant, personne n'est à l'aide de cordes pour les e/S de fichier plus. La nouvelle façon est d'utiliser des Données.ByteString (disponible sur le hackage), et de Données.ByteString.Paresseux quand vous voulez paresseux lit.
import qualified Data.ByteString as Str
main = do contents <- Str.readFile "foo"
-- readFile is strict, so the the entire string is read here
Str.putStr contents
ByteStrings sont la voie à suivre pour les grandes chaînes de caractères (comme le contenu du fichier). Ils sont beaucoup plus rapide et plus efficace en terme de mémoire de la Chaîne (= [Char]).
Notes:
J'ai importé le frr de Contrôle.En parallèle.Des stratégies uniquement pour des raisons de commodité. Vous pouvez écrire quelque chose comme vous-même assez facilement:
forceList [] = ()
forceList (x:xs) = forceList xs
- Ce juste une des forces de la traversée de la colonne vertébrale (pas les valeurs) de la liste, ce qui aurait pour effet de la lecture du fichier.
Paresseux I/O est en train de devenir considéré comme mauvais par des experts; je recommande l'utilisation stricte bytestrings pour la plupart des e/S de fichier pour le moment. Il y a quelques solutions dans le four qui tentent de ramener composable différentiels lit, le plus prometteur de ce qui est appelé "Iteratee" par Oleg.