【问题标题】:haskell conduits from file to process从文件到进程的haskell管道
【发布时间】:2016-08-15 12:49:58
【问题描述】:

如何从文件流式传输到进程中?

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)

唯一的MonadResourceResourceT,特别是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) ()

但我不知道如何使用它。

【问题讨论】:

  • 你在串流什么?以及到哪个过程?总的来说,你想做什么?
  • 我修正了我的答案。
  • 没有什么比使用sourceHandle 并自己关闭手柄那么简单了。 ResourceT 很好,但实际上只是为了方便。

标签: haskell monads monad-transformers conduit


【解决方案1】:

由于您能够提供 CreateProcess,因此您可以使用 CreateProcess 的重定向功能甚至 shell 从已知文件名重定向标准输入。

这里有一些例子。请注意,在每种情况下,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" )

更新

如果您想避免生成 shell,我创建了一个替代版本 sourceProcessWithStreams 从 CreateProcess 中获取标准输入:

Using UseProvidedHandle with streamingProcess

或者,您可以使用withFilesourceHandle

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

【讨论】:

  • 您好,感谢您的回复。关于原始答案,我想没有明确提到它(我认为它隐含在标题中),但我需要一条完整的管道,因为我需要处理输入和输出之间的数据。文件和过程仅仅是开始和结束。关于您的更新,我已经说过,如果可能的话,我不希望我们使用 sourceHandle,因为如果可能的话,我宁愿不处理我自己的文件打开和关闭。
  • 您的意思是要在将输入文件的内容通过另一个管道阶段发送到进程之前将其发送?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-21
  • 1970-01-01
  • 1970-01-01
  • 2016-04-22
  • 1970-01-01
  • 2017-05-02
  • 2018-06-24
相关资源
最近更新 更多