我正在使用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
是一个很好的选择,可以从导管流中获得一个值。
-- 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
但是这段代码有一个缺陷,我需要"意识到"。所有的惰性字节串都在内存中,这意味着它不能在固定空间中运行。
是否有任何方法,我可以使用管道
yield
一个懒惰的字节串,并将其保存到一个文件在恒定的内存?或者,任何其他不使用
sinkLazy
并解决保存到在恒定空间中运行的文件的问题的方法?
编辑
我还测试了将惰性字节流直接写入文件,如下所示,但这会消耗大约2倍于文件大小的内存。(writeFile
来自Data.ByteString.Lazy
)。
bytestream <- liftIO $ AWS.runResourceT $ runAwsT awsEnv $ getFile serviceBucket key
writeFile filename bytestream
像conduit
这样的流库的目的是实现惰性数据结构和操作(惰性ByteString
s,惰性I/O等)的一些好处,同时更好地控制内存使用。sinkLazy
函数的目的是将数据从具有良好控制的内存占用的conduit
生态系统中取出,并回到带有相关空间泄漏的惰性对象的狂野西部。所以,这就是你的问题。
与其将数据流从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)