如何使用Data.ByteString解析一个7GB的文件?

7

我需要解析一个文件,因此首先要读取它,以下是我的程序:

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 

当使用一个7GB文件调用时,执行过程会出现以下错误。

> ./tmp  big_big_file.dat
> tmp: {handle: big_big_file.dat}: hGet: illegal ByteString size (-1501792951): illegal operation

感谢您的回复!

@DanielFischer,你怎么称呼“平台”?如果是指操作系统的话,那我正在使用Linux Ubuntu 10.4。谢谢。 - Fopa Léon Constantin
32位还是64位?一般来说,32位操作系统在处理那么大的文件时会出现问题。 - Tyler Eaves
@DanielFischer,32位。 - Fopa Léon Constantin
ByteString 在所有平台上使用 Int,因此它们只支持最多 2GB。您需要使用惰性 ByteString才能使其正常工作。 - dflemstr
@dflemstr:在 GHC 中,64 位架构上的 Int 是 64 位的。 - ehird
@ehird,是的,但它仅保证有30个位元,因此,如果您想制作跨平台应用程序,应该使用最小公倍数。 - dflemstr
2个回答

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)

如果溢出,最有可能的结果是"illegal ByteString size"错误或分段错误。
如果有可能,请使用lazy ByteString处理如此大的文件。在您的情况下,您几乎必须这样做,因为使用32位Int,无法创建7GB的ByteString。
如果您需要将行处理为严格的ByteString,并且没有任何行过长,您可以通过lazy 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,那么整体性能可能会更好。


谢谢@DanielFischer!现在我明白了,但是我该怎么解析我的文件? - Fopa Léon Constantin
既然你把它分成了行,如果你确定没有任何一行超过2GB,那么你可以将文件读取为惰性的“ByteString”,将其拆分成行,如果必要,从每行制作一个严格的“ByteString”。或者你可以逐行读取文件。需要更多信息来确定最佳方法(但可能是通过惰性方式)。 - Daniel Fischer

5

严格的 ByteString 仅支持最多 2 GiB 的内存。您需要使用惰性ByteString才能正常工作。


哇哦!感谢 @dflemstr,它起作用了,就像你说的那样,只需将 Data.ByteString.Char8 更改为 Data.Bytestring.Lazy.Char8 - Fopa Léon Constantin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接