在大文件中寻找最有效的方法

Mat*_*hid 15 io performance haskell

在Haskell中处理真正大型二进制文件的最有效方法是什么?

标准答案是将整个文件作为惰性ByteString读取,然后使用Binary数据包之类的东西来编写解析器.这有几个问题......

首先,像Binary这样的库并没有真正处理解析失败,我明显地希望解析有时会失败.

其次,我没有解析整个文件内容.我将跳过它的大块.并且从磁盘读取数十亿字节的数据只是为了让垃圾收集器再次将其丢弃似乎相当不可靠.

与此相关,我需要能够判断我想要执行的跳过是否会将我从文件的末尾带走(如果出现错误则会出错).

我可能还需要向后搜索,或者可能需要查找文件中的特定字节偏移量,这似乎不是懒惰的ByteString方法所支持的.(最终将整个文件保存在RAM中存在严重危险.)

当然,另一种方法是逐个读取单个字节,与hSeek命令交错.但现在的问题是,一次读取一个字节的文件效率如何?听起来它可能很慢.我不确定是否会hSetBuffering对此产生影响.(?)

然后当然有mmap.但是,如果在大文件上使用虚拟内存系统,那似乎就会吓坏.(这很奇怪,考虑到它存在的全部目的......)

伙计们,我们怎么想?在I/O性能和代码可维护性方面,最好的方法是什么?

Yur*_*ras 2

我在使用 pdf 解析器时遇到了类似的问题。最初我使用iteratee包(它支持随机访问)。AFAIK 它是唯一支持随机 IO 的 IO 库。

目前的方法是基于io-streams包。我发现它更方便。性能足够好,attoparsec集成开箱即用,包含很多组合器。

以下是如何使用iteratee随机 IO 的基本示例:

shum@shum-laptop:/tmp/shum$ cat test.hs 

import qualified  Data.Iteratee as I
import qualified Data.Attoparsec.Iteratee as I
import qualified Data.Attoparsec.Char8 as P
import Control.Monad.IO.Class
import System.Environment

main :: IO ()
main = do
  [file] <- getArgs
  flip I.fileDriverRandom file $ do
    I.seek 20
    num1 <- I.parserToIteratee P.number
    liftIO $ print num1
    I.seek 10
    num2 <- I.parserToIteratee P.number
    liftIO $ print num2
shum@shum-laptop:/tmp/shum$ cat in.data 
111111111
222222222
333333333
shum@shum-laptop:/tmp/shum$ runhaskell test.hs in.data 
333333333
222222222
shum@shum-laptop:/tmp/shum$
Run Code Online (Sandbox Code Playgroud)