2012-04-04 22 views
7

tôi phải phân tích một tập tin, và thực sự là một phải đọc nó lần đầu tiên, đây là chương trình của tôi:Làm cách nào để phân tích cú pháp tệp 7GB bằng Data.ByteString?

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() 

nhưng, sau khi biên soạn

> ghc --make -O2 tmp.hs 

thực hiện đi qua các lỗi sau khi được gọi với một tập tin 7Gigabyte.

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

cảm ơn bạn đã trả lời!

+0

Bạn đang sử dụng nền tảng nào? –

+0

@DanielFischer bạn gọi 'nền tảng' là gì? Nếu đó là hệ điều hành, thì tôi đang sử dụng Linux ubuntu 10.4. Cảm ơn –

+0

32 bit hoặc 64? Nói chung, một hệ điều hành 32 bit sẽ gặp vấn đề với các tệp lớn. –

Trả lời

5

Nghiêm ngặt ByteString s chỉ hỗ trợ tối đa 2 GiB bộ nhớ. Bạn cần sử dụng lazy ByteStrings để thiết bị hoạt động.

+0

Whaou! Cảm ơn @dflemstr Nó hoạt động, chỉ bằng cách thay đổi 'Data.ByteString.Char8' thành' Data.Bytestring.Lazy.Char8' như bạn đã nói. –

9

Độ dài ByteString s là Int. Nếu Int là 32 bit, tệp 7 GB sẽ vượt quá phạm vi Int và yêu cầu bộ đệm sẽ có kích thước sai và có thể dễ dàng yêu cầu kích thước âm.

Mã cho readFile chuyển đổi kích thước tập tin để Int cho yêu cầu đệm

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

và nếu điều đó tràn, một lỗi "kích thước ByteString bất hợp pháp" hoặc một lỗi segmentation là kết quả khả thi nhất.

Nếu có thể, hãy sử dụng số ByteString s để xử lý các tệp lớn. Trong trường hợp của bạn, bạn khá nhiều phải làm cho nó có thể, vì với 32 bit Int s, một 7GB ByteString là không thể tạo ra.

Nếu bạn cần các dòng để nghiêm khắc ByteString s cho việc xử lý, và không có dòng là cực kỳ dài, bạn có thể đi qua lười biếng ByteString s để đạt được điều đó

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 

nhưng nếu bạn có thể sửa đổi xử lý của bạn để đối phó với lười biếng ByteString s, có thể sẽ tốt hơn tổng thể.

+0

Cảm ơn @DanielFischer! Điều này rõ ràng với tôi bây giờ, nhưng tôi có thể làm gì để phân tích cú pháp tệp của mình? –

+0

Vì bạn chia nó thành các dòng, nếu bạn chắc chắn rằng không có dòng nào dài hơn 2GB, bạn có thể đọc tệp dưới dạng 'ByteString' lười, tách thành dòng và nếu cần, hãy thực hiện' ByteString' nghiêm ngặt từ mỗi dòng. Hoặc bạn có thể đọc tệp theo từng dòng. Cần thêm thông tin để xác định phương pháp tiếp cận tốt nhất (nhưng có thể là do lười biếng). –