2012-04-04 8 views
7

tengo que analizar un archivo, y de hecho una que leerlo primero, aquí está mi programa:Cómo analizar un archivo de 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() 

pero, después de la compilación

> ghc --make -O2 tmp.hs 

la ejecución pasa por el siguiente error cuando llamado con un archivo de 7 Gigabytes.

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

gracias por cualquier respuesta!

+0

¿En qué plataforma estás? –

+0

@DanielFischer ¿cómo se llama 'plataforma'? si es el sistema operativo, entonces estoy usando Linux ubuntu 10.4. Gracias –

+0

32 bit or 64? En general, un sistema operativo de 32 bits va a tener problemas con archivos tan grandes. –

Respuesta

5

Strict ByteString s solo admiten hasta 2 GiB de memoria. Debe usar lazy ByteStrings para que funcione.

+0

Whaou! Gracias @dflemstr Funciona, simplemente cambiando 'Data.ByteString.Char8' a' Data.Bytestring.Lazy.Char8' como dijiste. –

9

La longitud de ByteString s es Int. Si Int es de 32 bits, un archivo de 7GB excederá el rango de Int y la solicitud de almacenamiento será de un tamaño incorrecto y puede solicitar fácilmente un tamaño negativo.

El código para readFile convierte el tamaño del archivo a Int para la solicitud de búfer

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

y si eso se desborda, un error "tamaño ilegal ByteString" o un fallo de segmentación son los resultados más probables.

Si es posible, use ByteString s perezosos para manejar archivos tan grandes. En su caso, tiene que hacerlo posible, ya que con 32 bit Int s, un 7GB ByteString es imposible de crear.

Si necesita que las líneas sean estrictos ByteString s para el trámite y no la línea es muy larga, puede pasar por perezosos ByteString s para lograr que

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 

pero si se puede modificar el procesamiento de tratar con ByteString s perezoso, que probablemente será mejor en general.

+0

Gracias @DanielFischer! Ahora lo tengo claro, pero ¿qué puedo hacer para analizar mi archivo? –

+0

Dado que lo divide en líneas, si está seguro de que ninguna línea supera los 2 GB, puede leer el archivo como un byteString perezoso, dividirlo en líneas y, si es necesario, crear un 'ByteString' estricto en cada línea. O puede leer el archivo línea por línea. Necesita más información para determinar el mejor enfoque (pero probablemente sea flojo). –

Cuestiones relacionadas