Каналы Haskell от файла к процессу

Как я могу поток из файла в процесс?

Data.Conduit.Binary.sourceFile :: MonadResource m => FilePath -> Producer m ByteString
Data.Conduit.Process.sourceProcessWithStreams :: CreateProcess -> Producer IO ByteString -> Consumer ByteString IO a -> Consumer ByteString IO b -> IO (ExitCode, a, b)

Единственное, что является MonadResource это ResourceT, особенно IO это не MonadResource,

Я вижу, что есть sourceHandle который IO, но я бы не стал обрабатывать свои собственные файлы, которые открываются и закрываются, если это возможно. Кроме того, я хочу понять эту проблему в случае, если я понимаю ее в другом месте.

Есть также Data.Conduit.Lift.distribute:

distribute :: (Monad (t (ConduitM b o m)), Monad m, Monad (t m), MonadTrans t, MFunctor t) => ConduitM b o (t m) () -> t (ConduitM b o m) () 

так что я бы получил что-то вроде

distribute $ sourceFile "foo" :: ResourceT (ConduitM i ByteString IO) ()

но я не знаю, как это использовать.

1 ответ

Так как вы можете поставить CreateProcess Вы можете перенаправить стандартный ввод с известного имени файла, используя возможности перенаправления CreateProcess или даже оболочка.

Вот несколько примеров. Обратите внимание, что в каждом случае wc сообщает статистику по файлу input а не поставляемый производитель (который является пустым производителем)

#!/usr/bin/env stack
{- stack runghc --resolver lts-6.0
    --package conduit-extra
    --package conduit-combinators
 -}
{-# LANGUAGE OverloadedStrings #-}

import Conduit
import Data.Conduit
import Data.Conduit.Process
import qualified Data.ByteString.Char8 as BS

ex1 = do x <- sourceCmdWithConsumer "date" lengthC
         print x

emit prefix = mapM_C (\x -> BS.putStr prefix >> BS.putStr ": " >> BS.putStrLn x)

ex2 = do let cp = shell "wc < input"
         x <- sourceProcessWithConsumer cp (emit "stdout")
         print x

ex3 = sourceCmdWithStreams "wc < input" (return ())  (emit "stdout") (emit "stderr")

ex4 = do let cp = shell "wc < input"
         sourceProcessWithStreams cp (return ()) (emit "stdout") (emit "stderr" )

Обновить

Если вы хотите избежать порождения оболочки, я создал альтернативную версию sourceProcessWithStreams, которая берет stdin из CreateProcess:

Использование UseProvidedHandle с streamingProcess

Кроме того, вы можете использовать withFile а также sourceHandle:

#!/usr/bin/env stack
{- stack runghc --resolver lts-6.0
    --package streaming-commons
    --package conduit
    --package conduit-extra
 -}

{-# LANGUAGE OverloadedStrings #-}

import System.IO
import qualified Data.ByteString.Char8 as BS
import Conduit
import System.Process
import Data.Conduit.Process

emit prefix = mapM_C $ \x -> BS.putStr prefix >> BS.putStr ": " >> BS.putStrLn x

ex3 = do let cp = (proc "wc" [])
         withFile "input" ReadMode $ \h -> do
           sourceProcessWithStreams cp (sourceHandle h) (emit "stdout") (emit "stderr")

main = ex3 >>= print
Другие вопросы по тегам