从Haskell中下载大文件的方法

7
有没有关于如何在Haskell中下载大文件的建议?我认为Http.Conduit是一个很好的库,但它是如何解决这个问题的呢?它的文档中有一个例子,但它不适用于文件的下载,它只能下载一个文件:
 import Data.Conduit.Binary (sinkFile)
 import Network.HTTP.Conduit
 import qualified Data.Conduit as C

 main :: IO ()
 main = do
      request <- parseUrl "http://google.com/"
      withManager $ \manager -> do
          response <- http request manager
          responseBody response C.$$+- sinkFile "google.html"

我希望能够下载大文件而不会耗尽内存,例如在性能方面有效地完成下载,同时能够"稍后"继续下载它们,即首先下载一部分,然后再下载另一部分。
我还发现 hackage上的download-curl软件包,但我不能确定它是否适合我,或者它是否像我需要的那样分块下载文件。

4
你为什么认为这个例子不能流式传输数据? - Carl
1
@Carl,如果是这样的话,你认为是为什么呢? - Incerteza
6
它使用导管。导管完全是关于数据流传输的。 - Carl
1
@AlexanderSupertramp http-clienthttp-conduit 的依赖之一。 - Sibi
好的,Data.Conduit是(它的文档证明了这一点),但是没有关于Network.HTTP.Conduit的证据。 - Incerteza
显示剩余3条评论
2个回答

12

Network.HTTP.Conduit提供了三个函数来执行请求:

在这三个函数中,前两个函数将使整个响应体存储在内存中。如果您想在恒定的内存中操作,则使用http函数。 http函数提供了一个通过ResumableSource访问流接口的方法。

您在代码中提供的示例使用交错I / O将响应正文写入文件以保持恒定的内存空间。因此,当下载大文件时,您不会耗尽内存。


withManager 不像你说的那样是一个 http 函数。它是逐块读取文件吗? - Incerteza
@AlexanderSupertramp withManager与读取文件无关,它只是跟踪打开的连接。 - Sibi

3
这对我来说有效:
import           Control.Monad.Trans.Resource (runResourceT)
import           Data.Conduit.Combinators     (sinkFile)
import           Network.HTTP.Conduit         (parseRequest)
import           Network.HTTP.Simple          (httpSink)


downloadFile :: String -> IO ()
downloadFile url = do
  request <- parseRequest url
  runResourceT $ httpSink request $ \_ -> sinkFile "tmpfile"

我同意这有点奇怪,为了这样一个任务需要四个不同的模块(来自3个包:conduitresourcethttp-conduit)。


我认为最后一行可以是 runConduitRes $ httpSource request getResponseBody .| sinkFile filename,整个程序只需要导入两个模块 (ConduitNetwork.HTTP.Simple)。 - orthocresol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接