parsing - Haskell:用二进制懒惰地读取二进制文件

标签 parsing haskell binary conduit

我正在尝试读取二进制文件并使用“二进制”包懒惰地解析它。包文档提供了一个示例,说明如何在不强制所有输入的情况下执行此操作,与我的场景非常相似:

 example2 :: BL.ByteString -> [Trade]
 example2 input
  | BL.null input = []
  | otherwise =
    let (trade, rest, _) = runGetState getTrade input 0
    in trade : example2 rest

但是,这使用了已弃用的 runGetState函数,它本身将您指向 runGetIncremental功能。

问题是'runGetIncremental' 函数似乎强制剩余的输入为严格的字节串,从而强制它将整个文件加载到内存中。事实上,当我尝试运行它时,我看到大约 6GB 的内存使用量。甚至执行runGetState现在似乎基于 runGetIncremental然后使用 chunk 将严格字节串重新转换回惰性字节串.

我可以获得教程中描述的行为,还是二进制文件现在不支持?如果是后者,最好的方法是什么?我有一点使用管道的经验,但我不清楚如何在这里使用它。

最佳答案

您可以使用 pipes-binary 执行此操作和 pipes-bytestring .这是一个帮助您的功能:

import Control.Monad (void)
import Data.Binary
import Pipes
import Pipes.Binary (decodeMany)
import Pipes.ByteString (fromHandle)
import qualified Pipes.Prelude as P
import System.IO

decodeHandle :: (Binary a) => Handle -> Producer a IO ()
decodeHandle handle = void $ decodeMany (fromHandle handle) >-> P.map snd
voidmap snd是因为 decodeMany实际上返回更多信息(如字节偏移和解析错误)。如果您确实需要该信息,则只需将其删除即可。

以下是您可能如何使用 decodeHandle 的示例, 使用快速骨架 Trade我拼凑起来:
data Trade = Trade

instance Binary Trade where
    get   = return Trade
    put _ = return ()

instance Show Trade where show _ = "Trade"

main = withFile "inFile.txt" ReadMode $ \handle -> runEffect $
    for (decodeHandle handle) $ \trade -> do
        lift $ print (trade :: Trade)
        -- do more with the parsed trade

您可以使用 for循环解码的交易并处理它们,或者如果您愿意,可以使用管道组合:
main = withFile "inFile.txt" ReadMode $ \handle -> runEffect $
    decodeHandle handle >-> P.print

这将是懒惰的,并且只会根据您的实际需要解码尽可能多的交易。所以如果你插入一个 take在解码器和打印机之间,它只会读取处理请求数量的交易所需的输入:
main = withFile "inFile.txt" ReadMode $ \handle -> runEffect $
    for (decodeHandle handle >-> P.take 4) $ \trade -> do
        ... -- This will only process the first 4 trades

-- or using purely pipe composition:

main = withFile "inFile.txt" ReadMode $ \handle -> runEffect $
    decodeHandle handle >-> P.take 4 >-> P.print

关于parsing - Haskell:用二进制懒惰地读取二进制文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19862583/

相关文章:

java - 如何使用三个参数将节点插入到 Treap 上

R:所有可能的唯一结果的二进制矩阵

java - 如何读取二进制文件中的整数和日期

java - 使用 poi xssf 和 sax 解析器解析 xlsx 文件的一部分

list - 如何在不多次遍历字符串的情况下跟踪字符串的多个属性?

Haskell 堆栈脚本额外依赖项

haskell - 将 ghc-options 传递给 Stack 脚本解释器

java - 在 Java 中读取一个 json 文件

java - 使用斯坦福解析器给出的解析分数检查句子的语法

ios - SwiftyStoreKit解析收据