2012-04-04 75 views
7

我要解析一個文件,確實是一個必須先讀它,這是我的計劃:如何使用Data.ByteString解析7GB文件?

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

你在哪個平臺上? – 2012-04-04 13:35:29

+0

@DanielFischer你叫'平臺'是什麼?如果它是操作系統,那麼我使用Linux ubuntu 10.4。謝謝 – 2012-04-04 13:37:23

+0

32位或64位?一般來說,一個32位的操作系統會遇到很大的文件問題。 – 2012-04-04 13:39:22

回答

5

嚴格ByteString s只支持高達2 GiB的內存。您需要使用lazy ByteStrings才能正常工作。

+0

Whaou!謝謝@dflemstr它的工作,只是通過改變'Data.ByteString.Char8'到'Data.Bytestring.Lazy.Char8'如你所說。 – 2012-04-04 13:49:40

9

ByteString s的長度爲Int。如果Int是32位,則7GB文件將超出Int的範圍,並且緩衝區請求將針對錯誤的大小並且可以容易地請求負大小。

readFile的代碼的文件大小轉換爲Int用於緩衝請求

readFile :: FilePath -> IO ByteString 
readFile f = bracket (openBinaryFile f ReadMode) hClose 
    (\h -> hFileSize h >>= hGet h . fromIntegral) 

並且如果溢出,一個「非法字節字符串尺寸」錯誤或段故障是最有可能的結果。

如果可能,請使用lazy ByteString s來處理大的文件。在你的情況下,你幾乎不得不讓它成爲可能,因爲使用32位Int秒,7GB ByteString是不可能創建的。

如果您需要的線路要嚴格ByteString S爲處理,並沒有行是非常長的,你可以通過懶ByteString s到實現這一

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 s,這可能會更好整體。

+0

謝謝@DanielFischer!現在我很清楚,但是我能做些什麼來解析我的文件? – 2012-04-04 13:45:18

+0

既然你把它分成幾行,如果你確定沒有一行長度超過2GB,你可以把文件看作一個懶惰的'ByteString',將它們分成幾行,如果需要的話,從每一行開始一個嚴格的'ByteString'。或者你可以逐行讀取文件。需要更多信息來確定最佳方法(但可能會經歷懶惰)。 – 2012-04-04 13:48:55