Каналы 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