我正在尝试调整此AWS S3 upload code以处理已知长度的Lazy ByteString
(因此不会强制在内存中完全读取它 - 它来自网络,其中长度为预先发送)。我似乎必须在Lazy ByteString
上定义GivesPopper
函数才能将其转换为RequestBodyStream
。由于定义了GivesPopper
的复杂方式,我不确定如何为Lazy ByteString
编写它。将会欣赏有关如何编写它的指示。 Here是用于从文件中读取的编写方式:
let file ="test"
-- streams large file content, without buffering more than 10k in memory
let streamer sink = withFile file ReadMode $ \h -> sink $ S.hGet h 10240
如果我理解正确的话,上面代码中的 streamer
类型为GivesPopper ()
。
如果Lazy ByteString
已知长度为len
,那么在GivesPopper
上编写{
"header": {
"messageId": "42e0bf9c-18e2-424f-bb11-f8a12df1a79e",
"name": "DiscoverAppliancesResponse",
"namespace": "Alexa.ConnectedHome.Discovery",
"payloadVersion": "2"
},
"payload": {
"discoveredAppliances": [
{
"actions": [
"incrementPercentage",
"decrementPercentage",
"setPercentage",
"turnOn",
"turnOff"
],
"applianceId": "0d6884ab-030e-8ff4-ffffaa15c06e0453",
"friendlyDescription": "Study Light connected to Loxone Kit",
"friendlyName": "Study Light",
"isReachable": true,
"manufacturerName": "Loxone",
"modelName": "Spot"
}
]
}
}
函数的好方法是什么?我们一次可以阅读一个块。
答案 0 :(得分:2)
这是你正在寻找的吗?
import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy as L
import System.IO
file = "test"
-- original streamer for feeding a sink from a file
streamer :: (IO S.ByteString -> IO r) -> IO r
streamer sink = withFile file ReadMode $ \h -> sink $ S.hGet h 10240
-- feed a lazy ByteString to sink
lstreamer :: L.ByteString -> (IO S.ByteString -> IO r) -> IO r
lstreamer lbs sink = sink (return (L.toStrict lbs))
lstreamer
类型检查,但可能并不完全符合您的要求。每次接收器调用它时,它只返回相同的数据。另一方面,S.hGet h ...
最终将返回空字符串。
这是一个使用IORef来跟踪我们是否应该开始返回空字符串的解决方案:
import Data.IORef
mklstream :: L.ByteString -> (IO S.ByteString -> IO r) -> IO r
mklstream lbs sink = do
ref <- newIORef False
let fetch :: IO S.ByteString
fetch = do sent <- readIORef ref
writeIORef ref True
if sent
then return S.empty
else return (L.toStrict lbs)
sink fetch
这里fetch
是获取下一个块的动作。第一次调用它时,您将获得原始的惰性字节串(严格的)。后续调用将始终返回空字符串。
<强>更新强>
以下是如何一次性捐出少量资金:
mklstream :: L.ByteString -> (IO S.ByteString -> IO r) -> IO r
mklstream lbs sink = do
ref <- newIORef (L.toChunks lbs)
let fetch :: IO S.ByteString
fetch = do chunks <- readIORef ref
case chunks of
[] -> return S.empty
(c:cs) -> do writeIORef ref cs
return c
sink fetch