haskell - 在 Haskell 中使用 Pipes 读写二进制数据

标签 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 不是管道的惯用用法,而是出于测试目的而提供的。

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

最佳答案

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

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

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

关于haskell - 在 Haskell 中使用 Pipes 读写二进制数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31567305/

相关文章:

java - 检查文件结尾未按预期工作

c - 如何在 C 中将文件中的数字字符串作为单独的整数存储在数组中

c - C 中与 Windows 10 的虚拟端口通信

haskell - 如何缩短这样的 Haskell 实现?

haskell - 如何在 Haskell 中制作具有不同行为的相同类型?

haskell - 是否可以实现 `(Applicative m) => Applicative (StateT s m)` ?

c - 逐行读取数字并将其拆分为 C 中的多个变量

haskell - 当共享值超出范围时如何处置/释放/"finalize"非托管资源

java - 如何在 QtJambi 中获取标准输入、标准输出、标准错误文本流的 QIODevice 实例?

java - 扫描仪在使用 next() 或 nextFoo() 后跳过 nextLine()?