我可以懒惰地读取n个文件作为Haskell中的单个IO操作吗?

Ben*_*err 5 io file-io haskell lazy-evaluation lazy-sequences

如何使用常量内存懒惰地将多个文件作为单个ByteString读取?

readFiles :: [FilePath] -> IO ByteString
Run Code Online (Sandbox Code Playgroud)

我目前有以下实现,但从我从分析中看到的以及我的理解,我将以n-1内存中的文件结束.

readFiles = foldl1 joinIOStrings . map ByteString.readFile
    where joinIOStrings ml mr = do
                                l <- ml
                                r <- mr
                                return $ l `ByteString.append` r
Run Code Online (Sandbox Code Playgroud)

我知道这里的缺陷是我正在应用IO操作然后重新打包它们所以我认为我需要的是一种替换它foldl1 joinIOStrings而不应用它们的方法.

Dan*_*her 7

如何使用常量内存懒惰地将多个文件作为单个ByteString读取?

如果你想要恒定的内存使用,你需要Data.ByteString.Lazy.一个严格的ByteString懒惰不能读,并需要O(sum of filesizes)记忆.

对于不太多的文件,只需读取它们(D.B.L.readFile懒惰地读取)并连接结果就可以了,

import qualified Data.ByteString.Lazy as L

readFiles :: [FilePath] -> IO L.ByteString
readFiles = fmap L.concat . mapM L.readFile
Run Code Online (Sandbox Code Playgroud)

mapM L.readFile将打开文件,但只有它被要求当读取每个文件的内容.

如果文件数量很大,那么操作系统允许单个进程允许的打开文件句柄限制可能会耗尽,您需要更复杂的东西.你可以煮自己的懒人版mapM,

import System.IO.Unsafe (unsafeInterleaveIO)

mapM_lazy :: [IO a] -> IO [a]
mapM_lazy [] = return []
mapM_lazy (x:xs) = do
              r <- x
              rs <- unsafeInterleaveIO (mapM_lazy xs)
              return (r:rs)
Run Code Online (Sandbox Code Playgroud)

这样,只有当需要其内容时才会打开每个文件,而以前读取的文件已经可以关闭.由于关闭句柄的时间无法保证,因此仍有可能仍然遇到资源限制.

或者您可以使用自己喜欢的iteratee,enumerator,conduit或任何包,解决了系统的方式的问题.它们中的每一个都有其自身的优点和缺点,如果编码正确,则消除了意外达到资源限制的可能性.