我正在学习 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 的回答。我建议完全阅读它。
Bellow 是我基于 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