【问题标题】:Haskell streaming downloadHaskell 流式下载
【发布时间】:2017-04-11 17:34:22
【问题描述】:

我发现使用流行的 Haskell 库进行流式下载的建议方法有两个:

如何将前者的代码修改为 (a) 保存到文件,以及 (b) 只打印一个(取 5 个)字节响应,而不是对标准输出的整个响应?

我对 (b) 的尝试是:

#!/usr/bin/env stack
{- stack --install-ghc --resolver lts-5.13 runghc
   --package http-conduit
 -}
{-# LANGUAGE OverloadedStrings #-}
import           Control.Monad.IO.Class (liftIO)
import qualified Data.ByteString        as S
import qualified Data.Conduit.List      as CL
import           Network.HTTP.Simple
import           System.IO              (stdout)

main :: IO ()
main = httpSink "http://httpbin.org/get" $ \response -> do
    liftIO $ putStrLn
           $ "The status code was: "
          ++ show (getResponseStatusCode response)

    CL.mapM_ (take 5) (S.hPut stdout)

这未能映射(采取 5),并建议我除其他外,我仍然不明白映射 monads 或 liftIO 是如何工作的。

另外,这个资源:

http://haskelliseasy.readthedocs.io/en/latest/#note-on-streaming

...给了我一个警告,“我知道自己在做什么,我希望对资源进行更细粒度的控制,例如流媒体”,这并不容易或普遍支持。

我看过的其他地方:

如果 Haskellverse 中有任何东西可以让这更容易,更像是 Python 的请求:

response = requests.get(URL, stream=True)
for i,chunk in enumerate(response.iter_content(BLOCK)):
  f.write(chunk)

我也很感激那里的提示,或者指向 2016 年最先进技术的指针。

【问题讨论】:

  • 你真的需要流式传输吗? (那么您是否一次获得了足够多的数据,以至于将其全部存储在内存中是不可接受的?)
  • 是的,我是。
  • 我可能应该选择更合理的字节数,比如一些 2^n...

标签: haskell conduit


【解决方案1】:

您可能正在从最新版本的http-conduit 中寻找httpSource。它的行为与 Python 的请求非常相似:返回一个块流。

保存到文件

这很简单,只需将源直接重定向到文件接收器。

#!/usr/bin/env stack
{- stack --install-ghc --resolver nightly-2016-11-26 runghc --package http-conduit -}

{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple (httpSource, getResponseBody)
import Conduit

main = runConduitRes $ httpSource "http://httpbin.org/get" getResponseBody
                    .| sinkFile "data_file"

只打印一个(取 5 个)字节响应

一旦我们有了来源,我们使用takeCE 5 获取前5 个字节,然后通过printC 打印这些。

#!/usr/bin/env stack
{- stack --install-ghc --resolver nightly-2016-11-26 runghc --package http-conduit -}

{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple (httpSource, getResponseBody)
import Data.ByteString (unpack)
import Conduit

main = runConduitRes $ httpSource "http://httpbin.org/get" getResponseBody
                    .| takeCE 5
                    .| printC

保存到文件并且只打印一个(取5个)字节响应

为此,您需要zipSinks,或者对于涉及压缩多个接收器的更一般情况ZipSink

#!/usr/bin/env stack
{- stack --install-ghc --resolver nightly-2016-11-26 runghc --package http-conduit -}

{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple (httpSource, getResponseBody)
import Data.ByteString (unpack)
import Data.Conduit.Internal (zipSinks)
import Conduit

main = runConduitRes $ httpSource "http://httpbin.org/get" getResponseBody
                    .| zipSinks (takeCE 5 .| printC)
                                (sinkFile "data_file")

【讨论】:

  • 实际上,takeCE 会准确地获取流的给定元素,也就是五个字节。
  • 抱歉,仍在学习管道和整个思维方式:对 /both/ 将 takeC5 流式传输到标准输出并接收到文件进行什么修改?
  • @Mittenchops 更新了答案。 ZipSourceZipSinkZipConduit 是您分叉/加入的朋友。
  • 谢谢,@Alec。我对如何设置解析器有点困惑,但是我运行了这个,并且多个接收器的分叉对我来说很有意义,比我原始示例中的 liftIO 和 mapM_ 更有意义。这很有帮助!
  • @Mittenchops 是的 - 我保留它是因为它看起来更好(从技术上讲,main 可以有 IO a)。如果你想强制main :: IO (),只需在main = 之后添加() <$ 并在整个runConduitRes ... "data_file") 正文周围添加括号。
猜你喜欢
  • 2012-12-24
  • 2016-10-11
  • 1970-01-01
  • 2020-04-10
  • 2011-04-30
  • 1970-01-01
  • 1970-01-01
  • 2017-07-23
  • 2013-12-30
相关资源
最近更新 更多