Haskell IO et la fermeture des fichiers
Quand j'ouvre un fichier pour la lecture en Haskell, j'ai constaté que je ne peux pas utiliser le contenu du fichier après sa fermeture. Par exemple, ce programme permettra d'imprimer le contenu d'un fichier:
main = do inFile <- openFile "foo" ReadMode
contents <- hGetContents inFile
putStr contents
hClose inFile
Je m'attendais à ce interchanger l' putStr
ligne avec la hClose
ligne aurait aucun effet, mais ce programme imprime rien:
main = do inFile <- openFile "foo" ReadMode
contents <- hGetContents inFile
hClose inFile
putStr contents
Pourquoi cela se produit? Je suppose qu'il a quelque chose à voir avec l'évaluation différée, mais j'ai pensé que ces expressions obtenir séquencé donc il ne serait pas un problème. Comment voulez-vous mettre en œuvre une fonction comme readFile
?
Vous devez vous connecter pour publier un commentaire.
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:
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.
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:
- 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.
rnf
devrait être:rnf contents 'seq' hClose inFile
, avec les backticks autour deseq
. Aussi,rnf
a été déplacé àControl.DeepSeq
.[Mise À Jour: Prélude.readFile provoque des problèmes comme décrit ci-dessous, mais le passage à l'aide de Données.ByteString versions de tout ce qui fonctionne: je n'ai plus l'exception.]
Haskell newbie, mais actuellement je n'ai pas acheter de la revendication que "readFile est stricte et ferme le fichier quand c'est fini":
Qui fonctionne comme il se dresse sur le fichier que j'ai été le tester, mais si vous commentez la putStrLn puis apparemment le writeFile échoue. (Intéressant de voir comment boiteux Haskell des messages d'exception sont, manque les numéros de ligne etc.)?
?!?!?
openFile: resource busy (file is locked)
. Qui serait compatible avec readFile être paresseux.C'est parce que hGetContents ne rien faire pour le moment: il est paresseux I/O. Uniquement lorsque vous utilisez la chaîne de résultat le fichier est lu (ou la partie de celle-ci est nécessaire). Si vous voulez forcer la lecture, vous pouvez calculer sa longueur, et d'utiliser la fonction de séquenceur à la force de la longueur d'évaluation. Paresseux I/O peut être cool, mais il peut aussi être source de confusion.
Pour plus d'informations, voir la partie sur les paresseux I/O dans Real World Haskell, par exemple.
Comme indiqué précédemment,
hGetContents
est paresseux.readFile
est stricte et ferme le fichier quand c'est fait:les rendements de la suite dans les Étreintes
où
foo
estIl est intéressant de noter,
seq
garantit uniquement que une partie de l'entrée est lu, pas tout cela:rendements
Une bonne ressource est: Faire Haskell programmes plus rapides et les plus petits: hGetContents, hClose, readFile
readFile
n'est pas stricte, comme mentionné, d'autre part, l'utilisation de$!
avechGetContents
est entièrement redondant.Si vous voulez garder votre IO paresseux, mais le faire en toute sécurité, de sorte que des erreurs comme cela ne se produit pas, l'utilisation d'un package conçu pour cela, comme coffre-paresseux-io. (Cependant, coffre-paresseux-io ne prend pas en charge bytestring I/O.)
L'explication est assez longue pour figurer ici. Pardonnez-moi pour la distribution d'une courte pointe seulement: vous devez lire à propos de "semi-fermé les descripteurs de fichiers" et "unsafePerformIO".
En bref - ce comportement est un compromis entre d'une sémantique de la clarté et de l'évaluation différée. Vous devriez différer hClose jusqu'à ce que vous êtes absolument sûr de woudnt faire quoi que ce soit du contenu du fichier (comme l'appellent dans le gestionnaire d'erreur, ou somesuch), ou d'utiliser quelque chose de plus hGetContents pour obtenir le contenu du fichier non paresseusement.
unsafePerformIO
est pertinente ici. Peut-êtreunsafeInterleaveIO
.