如果你只是想代碼,那就是:
procFile' iFile oFile = fileDriver (joinI $
enumLinesBS ><>
mapChunks (map rstrip) $
I.mapM_ (B.appendFile oFile))
iFile
解說:
這是一個過程分爲三個階段:首先你變換原料流進行流,那麼你申請你函數來轉換該線路流,並最終消耗流。由於rstrip
處於中間階段,因此它將創建一個流轉換器(Enumeratee)。
您可以使用mapChunks
或convStream
,但mapChunks
更簡單。區別在於mapChunks
不允許您跨越區塊邊界,而convStream
則更爲一般。我更喜歡convStream
,因爲它沒有公開任何底層實現,但是如果mapChunks
就足夠了,結果代碼通常會更短。
rstripE :: Monad m => Enumeratee [ByteString] [ByteString] m a
rstripE = mapChunks (map rstrip)
注意在rstripE
額外map
。外部流(這是rstrip的輸入)的類型爲[ByteString]
,所以我們需要將rstrip
映射到它上面。
爲了便於比較,這是它會是什麼樣子,如果用convStream實現:
rstripE' :: Enumeratee [ByteString] [ByteString] m a
rstripE' = convStream $ do
mLine <- I.peek
maybe (return B.empty) (\line -> I.drop 1 >> return (rstrip line)) mLine
這是更長的時間,而且它的效率較低,因爲它只會在應用這些rstrip功能一行,甚至儘管可能有更多的線路可用。它可以對所有當前可用的塊,這是更接近mapChunks
版本的工作:
rstripE'2 :: Enumeratee [ByteString] [ByteString] m a
rstripE'2 = convStream (liftM (map rstrip) getChunk)
無論如何,與現有剝離enumeratee,它很容易組成與enumLinesBS
enumeratee:
enumStripLines :: Monad m => Enumeratee ByteString [ByteString] m a
enumStripLines = enumLinesBS ><> rstripE
組成運算符><>
遵循與箭頭運算符>>>
相同的順序。 enumLinesBS
將流拆分成行,然後rstripE
將它們剝離。現在你只需要添加一個用戶(這是正常iteratee),你就大功告成了:
writer :: FilePath -> Iteratee [ByteString] IO()
writer fp = I.mapM_ (B.appendFile fp)
processFile iFile oFile =
enumFile defaultBufSize iFile (joinI $ enumStripLines $ writer oFile) >>= run
的fileDriver
功能快捷鍵簡單地列舉了一個文件,並運行所產生的iteratee(不幸的是,參數順序從enumFile切換):
procFile2 iFile oFile = fileDriver (joinI $ enumStripLines $ writer oFile) iFile
附錄:這裏是您需要convStream的額外能力的情況。假設你想將每兩行連接成一個。您不能使用mapChunks
。考慮塊是單獨元素時,[bytestring]
。 mapChunks
沒有提供任何訪問下一個塊的方法,所以沒有別的方法可以與它連接。隨着但是convStream
,這很簡單:
concatPairs = convStream $ do
line1 <- I.head
line2 <- I.head
return $ line1 `B.append` line2
這看起來即使在合用的風格更好,
convStream $ B.append <$> I.head <*> I.head
你能想到的convStream
的不斷消耗流的一部分與所提供的iteratee,然後發送轉變爲內在的消費者。有時甚至這還不夠普遍,因爲在每一步都會調用相同的迭代器。在這種情況下,可以使用unfoldConvStream
在連續迭代之間傳遞狀態。
convStream
和unfoldConvStream
也允許一次性動作,因爲流處理iteratee是一個monad變換器。
約翰,謝謝你這個非常詳細的答案!這正是我需要的。 –
兩個小注釋:rstripE的類型需要一個類型類別限定符(Monad m)=>,並且我的rstrip函數需要在最後粘合一個換行符以與enumLinesBS集成。否則,它就像一個魅力! –
感謝您指出了這一點,我添加了類型上下文。 –