检查文件的管道 header

Conduit that checks file header

我想在读取二进制文件的设置中使用 Conduit,检查它是否具有正确的 header,然后处理文件中的剩余数据。

尝试编写一个检查 header 的管道,然后将其余数据流式传输到以下管道,我 运行 遇到了麻烦。我让他们住在 Either String monad 中以进行一些异常处理。这是代码的简化版本(我知道有一个 Condiut.Attoparsec 模块,但现在我想自己写):

import Conduit (ConduitM, mapC, mapM_C, takeWhileCE) 
import Data.ByteString.Conversion (toByteString')

separator :: ByteString
separator = toByteString' '#' 

check :: ByteString -> Either String ()

confirmHeader :: ConduitM ByteString ByteString (Either String) ()
confirmHeader = do
  takeWhileC (/= separator) .| mapM_C check
  mapC id

separator 是预定义的 ByteString,表示 header 结束。如果 header 签出,行 mapC id 应该传递到流的其余部分。我遗漏了 check 的不重要细节。

检查 header 的部分有效。然而,最后一行除了看起来不雅和 non-idiomatic 之外不起作用。 运行 类似

runConduit $ yield (toByteString' "header#rest") .| confirmHeader .| sinkList

给出 Right [] 而不是我所希望的 Right ["rest"]。有任何想法吗?

您的 takeWhileC (/= separator) 占用了整个 ByteString:它不适用于 ByteString 的块!您可以使用 Data.Conduit.Binary 处理流的各个字节。下面的代码有效 "as expected" 我相信。

module Main (main) where

import           Conduit
import           Data.ByteString (ByteString)
import           Data.ByteString.Conversion (toByteString')
import           Data.Char (ord)
import qualified Data.Conduit.Binary as B
import           GHC.Word (Word8)

separator :: Word8
separator = toEnum $ ord '#'

check :: ByteString -> Either String ()
check _ = Right ()

confirmHeader :: ConduitM ByteString ByteString (Either String) ()
confirmHeader = do
  B.takeWhile (/= separator) .| mapM_C check
  B.drop 1 -- drop separator which stayed in stream
  mapC id

main :: IO ()
main = print . runConduit $
  yield (toByteString' "header#rest") .| confirmHeader .| sinkList

并且输出:

[nix-shell:/tmp]$ ghc C.hs -fforce-recomp -Wall -Werror -o Main && ./Main
[1 of 1] Compiling Main             ( C.hs, C.o )
Linking Main ...
Right ["rest"]