检查文件的管道 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"]
我想在读取二进制文件的设置中使用 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"]