【发布时间】:2011-10-03 20:47:39
【问题描述】:
我正在学习 Haskell Lazy IO。
我正在寻找一种优雅的方式来复制大文件 (8Gb),同时将复制进度打印到控制台。
考虑以下简单的程序,它以静默方式复制文件。
module Main where
import System
import qualified Data.ByteString.Lazy as B
main = do [from, to] <- getArgs
body <- B.readFile from
B.writeFile to body
想像有一个你想用于报告的回调函数:
onReadBytes :: Integer -> IO ()
onReadBytes count = putStrLn $ "Bytes read: " ++ (show count)
问题:如何将 onReadBytes 函数编织到 Lazy ByteString 中,以便在成功读取时回调它?或者如果这个设计不好,那Haskell的方法是什么?
注意:回调的频率并不重要,可以每 1024 字节或每 1 Mb 调用一次 -- 不重要
回答:非常感谢 camccann 的回答。建议通读一遍。
下面是我基于camccann的代码的代码版本,你可能会发现它很有用。
module Main where
import System
import System.IO
import qualified Data.ByteString.Lazy as B
main = do [from, to] <- getArgs
withFile from ReadMode $ \fromH ->
withFile to WriteMode $ \toH ->
copyH fromH toH $ \x -> putStrLn $ "Bytes copied: " ++ show x
copyH :: Handle -> Handle -> (Integer -> IO()) -> IO ()
copyH fromH toH onProgress =
copy (B.hGet fromH (256 * 1024)) (write toH) B.null onProgress
where write o x = do B.hPut o x
return . fromIntegral $ B.length x
copy :: (Monad m) => m a -> (a -> m Integer) -> (a -> Bool) -> (Integer -> m()) -> m()
copy = copy_ 0
copy_ :: (Monad m) => Integer -> m a -> (a -> m Integer) -> (a -> Bool) -> (Integer -> m()) -> m()
copy_ count inp outp done onProgress = do x <- inp
unless (done x) $
do n <- outp x
onProgress (n + count)
copy_ (n + count) inp outp done onProgress
【问题讨论】:
-
顺便说一句,你可以说
[from, to] <- getArgs -
作为一个类似的问题 - 有没有办法在纯计算上取得进展?
-
@monadic,这是一个类似的问题,但答案却大不相同。基本上,您的函数会返回一个包含所需结果和进度报告的对,进度报告“计算”的方式取决于结果的计算。然后在使用结果之前打印进度报告。如果您想了解更多详细信息,那么我建议您提出一个新问题。
标签: haskell io progress lazy-evaluation bytestring