我想处理一个太大而无法读入内存的二进制文件。目前,我使用ByteString.Lazy.readFile来传输字节。我认为使用streaming软件包使我的程序更快是一个好主意。但是,readFile
的{{3}}表示:
readFile :: FilePath -> (Stream (Of String) IO () -> IO a) -> IO a
使用类型为'Stream(Of String)IO()-> IO a'的函数读取文件的行,以将流转换为'IO a'类型的值。
因此,streaming
包仅读取ASCII文本文件?我可以使用该程序包以字节为单位读取二进制文件吗?
答案 0 :(得分:3)
为了详细说明@Cubic的评论,尽管人们普遍认为应该在生产代码中避免使用惰性I / O,而应使用流方法代替它,但这与性能没有直接关系。如果您正在编写程序来对大文件进行一次性处理,只要您现在可以运行良好的惰性I / O版本,那么可能就没有很好的 performance 理由来转换它了转到流媒体包。
实际上,流传输更有可能增加一些开销,因此,我怀疑在大多数情况下,优化的惰性I / O解决方案的性能将不及优化的流传输解决方案。
避免使用惰性I / O的主要原因是previously discussed on SO。简而言之,懒惰的I / O使得难以一致地管理资源(例如,文件句柄和网络套接字),难以推断出空间使用情况(例如,小的程序更改可能会导致内存使用量爆炸),并且如果有问题的I / O的时间和顺序很重要,则有时是“不安全的”(如果您只是读入一组文件和/或写出另一组文件,通常就不成问题了。)
用于读取和/或写入大文件的短时间运行实用程序可能是以惰性I / O风格编写的不错的候选人。只要它们在运行时没有任何明显的空间泄漏,就可以了。
答案 1 :(得分:2)
仅使用 streaming 和 bytestring ,就可以编写如下内容:
import Data.ByteString
import Streaming
import qualified Streaming.Prelude as S
import System.IO
fromHandle :: Int -> Handle -> Stream (Of ByteString) IO ()
fromHandle chunkSize h =
S.untilRight $ do bytes <- Data.ByteString.hGet h chunkSize
pure $ if Data.ByteString.null bytes then Right ()
else Left bytes
使用 bytestring 中的hGet
,null
和 streaming 中的untilRight
。您将需要使用withFile
来获取Handle
,并在回调中使用Stream
:
dump :: FilePath -> IO ()
dump file = withFile file ReadMode go
where
go :: Handle -> IO ()
go = S.mapM_ (Data.ByteString.hPut stdout) . fromHandle 4096