使用Pipes在Haskell中读取和写入二进制数据

时间:2015-07-22 15:17:53

标签: haskell io readfile writefile haskell-pipes

我试图在常量内存中读取和写入很多整数。我已经想出了如何将内存写入内存,但还没弄清楚如何将它们读回来。

import Control.Lens (zoom)
import System.IO (IOMode(..), withFile)
import Pipes
import qualified Pipes.Prelude as P
import qualified Pipes.ByteString as PB    
import qualified Pipes.Parse as P
import qualified Pipes.Binary as P

intStream :: Monad m => Proxy x' x () Int m b
intStream = go (0 :: Int) where
   go i = yield i >> go (i + 1)

decoder :: Monad m => Int ->  P.Parser P.ByteString m [Int]
decoder n = zoom (P.decoded . P.splitAt n) P.drawAll

main :: IO ()
main = do
    withFile "ints" WriteMode $ \h -> do
         runEffect $ for intStream P.encode >-> P.take 10000 >-> PB.toHandle h
    withFile "ints" ReadMode $ \h -> do
         xs <- P.evalStateT (decoder 10000000) (PB.fromHandle h)
         print xs

我从Pipes.Binary的文档中获得了解码器功能。但是,它会使用drawAll根据documentation drawAll而不是惯用的Pipes,并且是出于测试目的而提供的。

我的问题是如何修改decoder以便它不使用drawAll,因此不会将xs的所有值加载到内存中。因此,不是打印x的列表,而是可以P.map print通过从文件中读取的解码ints流。

1 个答案:

答案 0 :(得分:6)

文档说decoded是从字节流到解码值流的镜头。我们可以使用view中的lens

将后者从前者中删除
decoder :: Monad m => Int -> Producer P.ByteString m a -> Producer Int m ()
decoder n p = void (view P.decoded p) >-> P.take n

main :: IO ()
main = do
    withFile "ints" WriteMode $ \h -> do
         runEffect $ for intStream P.encode >-> P.take 10000 >-> PB.toHandle h
    withFile "ints" ReadMode $ \h -> do
         runEffect $ decoder 10000 (PB.fromHandle h) >-> P.print

我对pipes没有太多经验,我只是按照这里的类型。该程序似乎按预期运行。