2012-02-10 18 views
7

Quiero tomar los primeros cinco bytes del primer archivo en el archivo zip. Yo uso paquete de archivo ZIP para la descompresión:Cómo tomar lazy bytestring del archivo zip sin desbordamiento del montón

import qualified Data.ByteString.Lazy as L 
import Data.Maybe 
import System.Environment (getArgs) 

import Codec.Archive.Zip 

main = do 
    f:_ <- getArgs 
    print . L.take 5 . fromEntry . head . zEntries . toArchive =<< L.readFile f 

Este código funciona para archivos pequeños pero tengo desbordamiento de pila con los grandes. Por ejemplo:

./zip-arch test.zip +RTS -p -hy -M100M 

para este archive da este heap profile

+0

Ese perfil montón muestra el uso del montón de 130k, eso no es indicación de un problema. Voy a echar un vistazo a mí mismo. –

+0

@DanielFischer extraño, pero tengo este mensaje de error: Heap exhausted; El tamaño máximo de almacenamiento dinámico actual es 104857600 bytes (100 MB); use '+ RTS -M 'para aumentarlo. – tymmym

+0

@tymmym: 'fromEntry' utiliza la suma de comprobación CRC32 del paquete" digest ". hace crc32 invocando crc32 en zlib.h, esto puede consumir algo de memoria? No estoy seguro. – Nybble

Respuesta

1

He leído el explanation del autor archivo ZIP y decidí hacer las reparaciones recomendadas. He terminado con una nueva biblioteca: zip-conduit. Su característica principal es el uso constante de la memoria sin IO perezoso. Para tomar primeros cinco bytes del archivo de puño en el archivo zip se puede escribir:

import   System.Environment 
import   Data.Conduit 
import qualified Data.Conduit.Binary as CB 

import   Codec.Archive.Zip 

main = do 
    f:_ <- getArgs 
    res <- withArchive f $ do 
       name:_ <- fileNames 
       source <- getSource name 
       runResourceT $ source $$ CB.take 5 
    print res 
1

considere llamar a unzip. No es super haskelly, pero cumple su función. Quizás todos los que odian deberían pasar más tiempo reparando o reemplazando bibliotecas rotas como zip-archive y menos tiempo en stackoverflow.

Descargo de responsabilidad: no hay error al verificar el presente. esto puede derramar mangos. lazy i/o es floja.

import System.Environment (getArgs) 
import System.IO (hSetBinaryMode) 
import System.Process (StdStream(...), createProcess, proc, close_fds, std_out) 

import qualified Data.ByteString.Lazy as L 

unzipLBS :: FilePath -> IO L.ByteString 
unzipLBS file = do 
    let args = proc "unzip" ["-p", file] 
     args' = args { std_out = CreatePipe, close_fds = True } 

    (_, Just hOut, _, _) <- createProcess args' 
    hSetBinaryMode hOut True 
    L.hGetContents hOut 

main :: IO() 
main = do 
    f:_ <- getArgs 
    print . L.take 5 =<< unzipLBS f 

parece funcionar:

$ runghc -Wall unzip.hs ~/Downloads/test.zip 
Chunk ",+\227F\149" Empty 
Cuestiones relacionadas