【发布时间】:2013-03-15 18:15:06
【问题描述】:
我正在尝试使用 Haskell 中的 pipe-attoparsec 解析二进制数据。涉及管道(代理)的原因是将读取与解析交错,以避免大文件占用大量内存。许多二进制格式基于块(或块),它们的大小通常由文件中的字段描述。我不确定这样一个块的解析器被称为什么,但这就是我在标题中所说的“子解析器”的意思。我遇到的问题是以简洁的方式实现它们,而不会占用大量内存。我想出了两个在某些方面都失败的替代方案。
备选方案 1 是将块读入单独的字节串并为其启动单独的解析器。虽然简洁,但大块会导致高内存使用。
备选方案 2 是在相同的上下文中保持解析并跟踪消耗的字节数。这种跟踪很容易出错,并且似乎感染了构成最终 blockParser 的所有解析器。对于格式错误的输入文件,在比较跟踪的大小之前,它还可能会在比 size 字段指示的范围内进一步解析,从而浪费时间。
import Control.Proxy.Attoparsec
import Control.Proxy.Trans.Either
import Data.Attoparsec as P
import Data.Attoparsec.Binary
import qualified Data.ByteString as BS
parser = do
size <- fromIntegral <$> anyWord32le
-- alternative 1 (ignore the Either for simplicity):
Right result <- parseOnly blockParser <$> P.take size
return result
-- alternative 2
(result, trackedSize) <- blockparser
when (size /= trackedSize) $ fail "size mismatch"
return result
blockParser = undefined
main = withBinaryFile "bin" ReadMode go where
go h = fmap print . runProxy . runEitherK $ session h
session h = printD <-< parserD parser <-< throwParsingErrors <-< parserInputD <-< readChunk h 128
readChunk h n () = runIdentityP go where
go = do
c <- lift $ BS.hGet h n
unless (BS.null c) $ respond c *> go
【问题讨论】:
标签: parsing haskell attoparsec haskell-pipes