我必须解析一个文件,确实必须首先阅读它,这是我的程序:
import qualified Data.ByteString.Char8 as B
import System.Environment
main = do
args <- getArgs
let path = args !! 0
content <- B.readFile path
let lines = B.lines content
foobar lines
foobar :: [B.ByteString] -> IO()
foobar _ = return ()
但是,在编译之后
> ghc --make -O2 tmp.hs
使用7G文件调用时,执行会发生以下错误。
> ./tmp big_big_file.dat
> tmp: {handle: big_big_file.dat}: hGet: illegal ByteString size (-1501792951): illegal operation
感谢您的回复!
答案 0 :(得分:9)
ByteString
的长度为Int
。如果Int
为32位,则7GB文件将超出Int
的范围,缓冲区请求的大小将错误,并且可以轻松请求负大小。
readFile
的代码将文件大小转换为缓存请求的Int
readFile :: FilePath -> IO ByteString
readFile f = bracket (openBinaryFile f ReadMode) hClose
(\h -> hFileSize h >>= hGet h . fromIntegral)
如果溢出,“非法ByteString大小”错误或分段错误是最可能的结果。
如果可能,请使用lazy ByteString
来处理大文件。在您的情况下,您几乎必须使其成为可能,因为使用32位Int
s,无法创建7GB ByteString
。
如果您需要对行进行严格ByteString
的行,并且没有行非常长,您可以通过惰性ByteString
来实现
import qualified Data.ByteString.Lazy.Char8 as LC
import qualified Data.ByteString.Char8 as C
main = do
...
content <- LC.readFile path
let llns = LC.lines content
slns = map (C.concat . LC.toChunks) llns
foobar slns
但如果您可以修改处理懒惰ByteString
的处理,那么总体上可能会更好。
答案 1 :(得分:5)
严格ByteString
仅支持最多2 GiB的内存。您需要使用lazy ByteString
s才能生效。