如何使用 conduit 获取惰性 ByteString 并将其写入文件(在常量内存中)

How to take a lazy ByteString and write it to a file (in constant memory) using conduit

我正在使用 amazonka 流式传输 S3 文件的下载,我使用 sinkBody 函数继续流式传输。目前我下载的文件如下:

getFile bucketName fileName = do
    resp <- send (getObject (BucketName bucketName) fileName)
    sinkBody (resp ^. gorsBody) sinkLazy

其中 sinkBody :: MonadIO m => RsBody -> ConduitM ByteString Void (ResourceT IO) a -> m a。为了在常量内存中 运行,我认为 sinkLazy 是从管道流中获取值的一个很好的选择。

在此之后,我想将惰性字节串数据(S3 文件)保存到本地文件中,为此我使用以下代码:

-- fetch stream of data from S3
bytestream <- liftIO $ AWS.runResourceT $ runAwsT awsEnv $ getFile serviceBucket key

-- create a file
liftIO $ writeFile filePath  ""

-- write content of stream into the file (strict version), keeps data in memory...
liftIO $ runConduitRes $ yield bytestream .| mapC B.toStrict .| sinkFile filePath

但是这段代码有一个缺陷,我需要在内存中“实现”所有的惰性字节串,这意味着它不能运行 in constant space.

编辑

我也测试了将惰性字节流直接写到文件中,如下,但是这样消耗的内存大约是文件大小的2倍。 (writeFile 来自 Data.ByteString.Lazy)。

bytestream <- liftIO $ AWS.runResourceT $ runAwsT awsEnv $ getFile serviceBucket key
writeFile filename bytestream

嗯,像 conduit 这样的流式库的目的是实现惰性数据结构和操作的一些好处(惰性 ByteStrings、惰性 I/O 等。 ) 同时更好地控制内存使用。 sinkLazy 函数的目的是将数据从 conduit 生态系统中取出,其内存占用控制良好,并返回到具有相关 space 泄漏的惰性对象的狂野西部。所以,这就是你的问题。

与其将流从 conduit 中导出并放入惰性 ByteString,您可能希望将数据保留在 conduit 中并将流直接导入文件中,使用类似于 sinkFile。我没有启动 AWS 测试程序 运行,但以下类型检查并可能会执行您想要的操作:

import Conduit
import Control.Lens
import Network.AWS
import Network.AWS.S3

getFile bucketName fileName outputFileName = do
    resp <- send (getObject (BucketName bucketName) fileName)
    sinkBody (resp ^. gorsBody) (sinkFile outputFileName)