[英]Haskell: Lazily read binary file with binary
我正在嘗試讀取二進制文件並使用'binary'包來懶散地解析它。 包文檔提供了一個如何執行此操作的示例,而不強制與我非常類似的場景的所有輸入:
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
將strict字符串重新轉換回惰性字符串。
我可以獲得教程中描述的行為,還是二進制文件現在不支持? 如果是后者,那么最好的方法是什么? 我有一點使用管道的經驗,但我不清楚如何在這里使用它。
您可以使用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
void
和map snd
在那里,因為decodeMany
實際上返回更多信息(如字節偏移和解析錯誤)。 如果您確實需要該信息,那么只需刪除它們即可。
下面是一個如何使用decodeHandle
,使用快速骨架進行Trade
I匯總:
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.