2012-02-10 1 views
7

Voglio prendere i primi cinque byte dal file pugno nell'archivio zip. Io uso pacchetto zip-archivio per la decompressione:Come eseguire pigri test dall'archivio zip senza overflow di heap

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 

Questo codice funziona per i piccoli archivi, ma ho avuto heap overflow con quelli più grandi. Per esempio:

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

per questo archive dà questo heap profile

+0

Quel profilo dell'heap mostra un utilizzo dell'heap di 130k, che non indica alcun problema. Daro 'un'occhiata da solo. –

+0

@DanielFischer strano, ma ho ricevuto questo messaggio di errore: Heap esaurito; La dimensione heap massima corrente è 104857600 byte (100 MB); usa '+ RTS -M 'per aumentarlo. – tymmym

+0

@tymmym: 'fromEntry' utilizza il checksum CRC32 dal pacchetto" digest ". fa crc32 invocando crc32 in zlib.h, questo potrebbe consumare un po 'di memoria? Non ne sono sicuro. – Nybble

risposta

1

Ho letto l'explanation dell'autore archivio zip e ha deciso di fare le riparazioni consigliate. Ho finito con una nuova libreria - zip-conduit. La sua caratteristica principale è l'utilizzo costante della memoria senza IO pigro. Per prendere i primi cinque byte dal file pugno nell'archivio zip puoi scrivere:

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

consideri chiamando a unzip. Non è super haskelly ma fa il lavoro. Forse tutti gli odiatori là fuori dovrebbero passare più tempo a riparare o sostituire librerie danneggiate come zip-archive e meno tempo su StackOverflow.

Disclaimer standard: nessun controllo degli errori presente. questo potrebbe perdere maniglie. l'i/o pigro è pigro.

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 

sembra funzionare:

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