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

Kik*_*dez 5 haskell lazy-evaluation conduit

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

getFile bucketName fileName = do
    resp <- send (getObject (BucketName bucketName) fileName)
    sinkBody (resp ^. gorsBody) sinkLazy
Run Code Online (Sandbox Code Playgroud)

在哪里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
Run Code Online (Sandbox Code Playgroud)

但这段代码有一个缺陷,我需要“实现”内存中的所有惰性字节串,这意味着它无法在常量空间中运行。

  • 有什么方法可以将管道用于yield惰性字节串并将其保存到常量内存中的文件中吗?

  • 或者,任何其他不使用sinkLazy并解决保存到在恒定空间中运行的文件的问题的方法?

编辑

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

bytestream <- liftIO $ AWS.runResourceT $ runAwsT awsEnv $ getFile serviceBucket key
writeFile filename bytestream
Run Code Online (Sandbox Code Playgroud)

K. *_*uhr 4

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

您可能希望保留数据并将流直接放入conduit文件中,而不是使用诸如. 我没有启动并运行 AWS 测试程序,但以下类型检查可能会执行您想要的操作:ByteStringconduitsinkFile

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)
Run Code Online (Sandbox Code Playgroud)