Как извлечь lazy bytestring из zip-архива без переполнения кучи - PullRequest
7 голосов
/ 10 февраля 2012

Я хочу взять первые пять байтов из первого файла в zip-архиве.Я использую пакет zip-архива для распаковки:

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

Этот код работает для небольших архивов, но у меня переполнение кучи большими.Например:

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

для этого архива дает этот профиль кучи

Ответы [ 2 ]

1 голос
/ 13 августа 2012

Я прочитал объяснение автора zip-архива и решил сделать рекомендованный ремонт.Я закончил с новой библиотекой - почтовый канал .Его главная особенность - постоянное использование памяти без ленивого ввода-вывода.Чтобы взять первые пять байтов из первого файла в zip-архиве, вы можете написать:

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 голос
/ 10 февраля 2012

Подумайте над тем, чтобы позвонить на распаковать .Это не супер, но это делает работу.Возможно, все ненавистники должны тратить больше времени на исправление или замену поврежденных библиотек, таких как zip-архив и меньше времени на стекпотоки.

Стандартный отказ от ответственности: проверка ошибок отсутствует.это может привести к утечке ручек.ленивый ввод-вывод ленивый.

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

Кажется, работает:

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