2012-04-04 13 views
7

devo analizzare un file, e in effetti un dovere leggerlo prima, qui è il mio programma:Come analizzare un file da 7 GB, con 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() 

ma, dopo la compilazione

> ghc --make -O2 tmp.hs 

l'esecuzione passa attraverso il seguente errore quando chiamato con un file 7Gigabyte.

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

grazie per qualsiasi risposta!

+0

Quale piattaforma sei? –

+0

@DanielFischer come si chiama 'piattaforma'? se è il sistema operativo, allora sto usando Linux ubuntu 10.4. Grazie –

+0

32 bit o 64? In generale un sistema operativo a 32 bit avrà problemi con file così grandi. –

risposta

5

Strict ByteString s supporta solo fino a 2 GB di memoria. È necessario utilizzare lazy ByteStrings perché funzioni.

+0

Whaou! Grazie a @dflemstr Funziona, cambiando 'Data.ByteString.Char8' in' Data.Bytestring.Lazy.Char8' come hai detto tu. –

9

La lunghezza di ByteString s è Int. Se Int è a 32 bit, un file da 7 GB supererà l'intervallo di Int e la richiesta di buffer avrà una dimensione errata e può facilmente richiedere una dimensione negativa.

Il codice per readFile converte la dimensione del file per Int per la richiesta di buffer

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

e se questo overflow, un errore "formato ByteString illegali" o un errore di segmentazione sono le più probabili esiti.

Se possibile, utilizzare lazy ByteString s per gestire file così grandi. Nel tuo caso, devi praticamente renderlo possibile, poiché con 32 bit Int s, è impossibile creare un 7GB ByteString.

Se è necessario le linee di essere rigorosi ByteString s per la lavorazione, e nessuna linea è estremamente lungo, si può passare attraverso pigri ByteString s per raggiungere tale

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 

ma se è possibile modificare la trasformazione di trattare con pigro ByteString s, che sarà probabilmente migliore nel complesso.

+0

Grazie @DanielFischer! Ora è chiaro per me, ma cosa posso fare per analizzare il mio file? –

+0

Dato che è stato diviso in righe, se si è certi che nessuna riga è più lunga di 2 GB, è possibile leggere il file come "ByteString" pigro, dividerlo in righe e, se necessario, eseguire un rigoroso 'ByteString' da ogni riga. O puoi leggere il file riga per riga. Ha bisogno di più informazioni per determinare l'approccio migliore (ma probabilmente sta passando attraverso il pigro). –

Problemi correlati