2016-08-15 3 views
1

Как я могу передать поток из файла в процесс?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)() 

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

+0

Что вы потокового? И к какому процессу? И вообще, что вы пытаетесь сделать? – Sibi

+0

Я исправил свой ответ. – ErikR

+0

Ничего, что вы сможете приготовить, будет почти таким же простым, как использование 'sourceHandle' и закрытие дескриптора самостоятельно. 'ResourceT' хорош, но это действительно просто удобство. – Michael

ответ

0

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

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

#!/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") 

Update

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

Using UseProvidedHandle with 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 
+0

Привет, спасибо за ваш ответ. Что касается первоначального ответа, я предполагаю, что он не упоминал об этом явно (я предполагал, что он неявный в заголовке), но мне нужна целая линия кабелепровода, потому что мне нужно обрабатывать данные между входом и выходом. Файл и процесс - это только начало и конец. Что касается вашего обновления, я уже сказал, что предпочел бы нам не использовать sourceHandle, если это возможно, потому что я бы предпочел не обрабатывать свой собственный файл, открывая и закрывая, если это возможно. – Tristan

+0

Вы хотите сказать, что хотите отправить содержимое входного файла через другой этап кабелепровода, прежде чем передать его в процесс? – ErikR