Я лечу 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
Imgine есть функция обратного вызова, которую вы хотите использовать для отчетности:
onReadBytes :: Integer -> IO ()
onReadBytes count = putStrLn $ "Bytes read: " ++ (show count)
ВОПРОС: , как переплетать функцию onReadBytes в Lazy ByteString, чтобы она была возвращена на успешное чтение? Или, если этот проект не очень хорош, то каков способ Haskell сделать это?
ПРИМЕЧАНИЕ: частота обратного вызова не важна, ее можно вызывать каждые 1024 байта или каждые 1 Мб - не важно
ОТВЕТ: Огромное спасибо камканне за ответ. Я предлагаю прочитать его полностью.
Bellow - это моя версия кода, основанная на кодеке на карте, вам может показаться полезным.
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