Haskell IO和关闭文件 [英] Haskell IO and closing files

查看:137
本文介绍了Haskell IO和关闭文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我在Haskell中打开一个阅读文件时,我发现在关闭文件后我不能使用这个文件的内容。例如,这个程序将会打印一个文件的内容:

$ p $ main = do inFile < - openFilefooReadMode
contents <-hGetContents inFile
putStr contents
hClose inFile

我期望交换 putStr 行与 hClose 行不起作用,但是这个程序不会打印任何内容:

  main = do inFile<  -  openFilefooReadMode 
contents< - hGetContents inFile
hClose inFile
putStr内容

为什么会发生这种情况?我猜这与懒惰评估有关,但我认为这些表达式会被排序,所以不会有问题。你将如何实现像 readFile

解决方案

说,这是因为懒惰的评价。操作完成后,手柄半关,所有数据读取后自动关闭。 hGetContents和readFile都是这样懒的。如果您在处理开放时遇到问题,通常您只需强制读取。这是简单的方法:

pre $ import $ Control $并行策略
- rnf表示减少到正常
main = do inFile< - openFilefoo
contents< - hGetContents inFile
rnf contents`seq` hClose inFile - 强制读取整个文件,然后关闭
putStr内容

然而,现在没有人使用字符串作为文件I / O了。新的方法是使用Data.ByteString(在hackage上可用)和Data.ByteString.Lazy,当你想读取懒惰的读取时。

 导入限定的Data.ByteString为Str 

main =做内容< - Str.readFilefoo
- readFile是严格的,所以整个字符串读在这里
Str.putStr内容

ByteStrings是去大字符串(如文件内容)。它们比字符串(= [Char])快得多并且内存效率更高。

注释:

我只是为了方便而从Control.Parallel.Strategies中导入了rnf。你可以很容易地写出类似的东西:

  forceList [] =()
forceList(x:xs) = forceList xs

这只是强制遍历列表(而不是列表的值)会有读取整个文件的效果。



懒惰I / O被专家视为邪恶;我建议暂时使用严格的字节串作为大部分的文件I / O。在烤箱中有几个解决方案试图带回可组合的增量式读取,其中最有希望的是由Oleg称之为Iteratee。


When I open a file for reading in Haskell, I've found that I can't use the contents of the file after closing it. For example, this program will print the contents of a file:

main = do inFile <- openFile "foo" ReadMode
          contents <- hGetContents inFile
          putStr contents
          hClose inFile

I expected that interchanging the putStr line with the hClose line would have no effect, but this program prints nothing:

main = do inFile <- openFile "foo" ReadMode
          contents <- hGetContents inFile
          hClose inFile
          putStr contents

Why does this happen? I'm guessing it has something to do with lazy evaluation, but I thought these expressions would get sequenced so there wouldn't be a problem. How would you implement a function like readFile?

解决方案

As others have stated, it is because of lazy evaluation. The handle is half-closed after this operation, and will be closed automatically when all data is read. Both hGetContents and readFile are lazy in this way. In cases where you're having issues with handles being kept open, typically you just force the read. Here's the easy way:

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

These days, however, nobody is using strings for file I/O anymore. The new way is to use Data.ByteString (available on hackage), and Data.ByteString.Lazy when you want lazy reads.

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 are the way to go for big strings (like file contents). They are much faster and more memory efficient than String (= [Char]).

Notes:

I imported rnf from Control.Parallel.Strategies only for convenience. You could write something like it yourself pretty easily:

  forceList [] = ()
  forceList (x:xs) = forceList xs

This just forces a traversal of the spine (not the values) of the list, which would have the effect of reading the whole file.

Lazy I/O is becoming considered evil by experts; I recommend using strict bytestrings for most of file I/O for the time being. There are a few solutions in the oven which attempt to bring back composable incremental reads, the most promising of which is called "Iteratee" by Oleg.

这篇关于Haskell IO和关闭文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆