mig*_*yte 19 binary serialization haskell stream lazy-evaluation
我一直在使用Data.Binary将数据序列化为文件.在我的应用程序中,我逐步向这些文件添加项目.两个最流行的序列化包,二进制和谷物,两个序列化列表作为计数后跟列表项.因此,我无法附加到我的序列化文件.我目前读取整个文件,反序列化列表,附加到列表,重新序列化列表,并将其写回文件.但是,我的数据集越来越大,我开始耗尽内存.我可以绕过拆箱我的数据结构以获得一些空间,但这种方法不能扩展.
一种解决方案是使文件格式下降和更改以更改初始计数,然后只需附加我的元素.但这并不令人满意,更不用说由于打破抽象而对文件格式的未来变化敏感.Iteratees/Enumerators在这里成为一个有吸引力的选择.我找了一个库,将它们与二进制序列化相结合,但没有找到任何东西.有谁知道这是否已经完成?如果没有,那么这个库是否有用?或者我错过了什么?
所以我说坚持下去,Data.Binary
但为可增长的列表编写一个新的实例.这是当前(严格)实例:
instance Binary a => Binary [a] where
put l = put (length l) >> mapM_ put l
get = do n <- get :: Get Int
getMany n
-- | 'getMany n' get 'n' elements in order, without blowing the stack.
getMany :: Binary a => Int -> Get [a]
getMany n = go [] n
where
go xs 0 = return $! reverse xs
go xs i = do x <- get
x `seq` go (x:xs) (i-1)
{-# INLINE getMany #-}
Run Code Online (Sandbox Code Playgroud)
现在,允许您流式传输(以二进制形式)附加到文件的版本需要急切或懒惰.懒惰的版本是最微不足道的.就像是:
import Data.Binary
newtype Stream a = Stream { unstream :: [a] }
instance Binary a => Binary (Stream a) where
put (Stream []) = putWord8 0
put (Stream (x:xs)) = putWord8 1 >> put x >> put (Stream xs)
get = do
t <- getWord8
case t of
0 -> return (Stream [])
1 -> do x <- get
Stream xs <- get
return (Stream (x:xs))
Run Code Online (Sandbox Code Playgroud)
适当的按摩适用于流式传输.现在,为了处理静默附加,我们需要能够0
在添加更多元素之前寻找文件的末尾并覆盖最终标记.