2013-11-21 104 views
5

正如標題所示,我希望能夠使用zip-conduit(壓縮文件)從zip壓縮文件內的文件讀取行我正在處理的是非常大的,所以我需要能夠在常量內存中執行此操作)。我很喜歡管道的基本概念,但從未在憤怒中使用過它們,並且對於從哪裏開始感覺相當困難。我已閱讀導管教程,但遇到麻煩與我的問題相匹配。使用Haskell的zip-conduit從zip壓縮文件中的文件讀取行

拉鍊,管道文件說,人們可以從一個zip壓縮包通過源的東西像下面這樣:

import qualified Data.Conduit.Binary as CB 
import Codec.Archive.Zip 

withArchive archivePath $ do 
    name:_ <- entryNames 
    sourceEntry name $ CB.sinkFile name 

我相信什麼,我需要做的是寫到位CB.sinkFile東西。 Data.Conduit.Text有一個lines函數 - 可以以某種方式使用它來獲取文件中的行嗎?

我真的很感激一個簡單的例子,比如說使用putStrLn寫出一個簡單的文本文件的行,這些文本文件存檔在一個zip文件中。提前致謝。

回答

6

邁克爾的答案,但有zip-conduit

import   Control.Monad.IO.Class (liftIO) 
import   Data.Conduit 
import qualified Data.Conduit.List as CL 
import qualified Data.Conduit.Text as CT 
import   Codec.Archive.Zip 

main :: IO() 
main = withArchive "input.zip" $ do 
    n:_ <- entryNames 
    sourceEntry n 
    $ CT.decode CT.utf8 
    =$ CT.lines 
    =$ CL.mapM_ (\t -> liftIO $ putStrLn $ "Got a line: " ++ show t) 
+0

非常感謝,這更有意義。使用導管使我的代碼更清潔。 – Chris

1

這裏有一個簡單的例子:

import   Control.Monad.IO.Class (liftIO) 
import   Data.Conduit 
import qualified Data.Conduit.Binary as CB 
import qualified Data.Conduit.List  as CL 
import qualified Data.Conduit.Text  as CT 

main :: IO() 
main = runResourceT 
    $ CB.sourceFile "input.txt" 
    $$ CT.decode CT.utf8 
    =$ CT.lines 
    =$ CL.mapM_ (\t -> liftIO $ putStrLn $ "Got a line: " ++ show t) 

您也可以view and experiment on FP Haskell Center

+1

感謝您抽出寶貴的時間來回復,邁克爾。你的例子演示了管道的一般用法(我從管道教程中瞭解到),但沒有說明如何使用我的問題中概述的zip-conduit,並且恐怕我太笨了,不能立即跳轉從你的例子到解決方案。進一步的幫助真的會感激! – Chris

+0

該示例不起作用:獲取「變量不在範圍內:main :: [GHC.Types.Char] - > t」 – Christophe

1

下面是一個簡單示例 -

import Data.ByteString as B 
import Data.Conduit 
import qualified Data.Conduit.List as CL 
import qualified Data.Conduit.Binary as CB 
import Codec.Archive.Zip 
import System.Environment 

sink :: Monad m => Sink ByteString m [ByteString] 
sink = CL.consume 

main::IO() 
main = do 
    [archivePath] <- getArgs 
    res <- withArchive archivePath $ do 
     name:_ <- entryNames 
     source <- getSource name 
     runResourceT $ (source $$ sink) 

    print res 

您可以處理該數據,因爲它在宿功能來通過(如使用CL需要,CB功能消耗),或者由於數據被懶惰地返回,你可以修改res中的數據。

+0

感謝您的支持,@jamshidh。但是,我將如何處理彙集函數中的東西?如果我將'res'轉換爲字符串列表並處理這些列表,我發現列表中的元素遠遠少於應該有的元素。項目的數量似乎受到它們所需內存的限制。我不確定'res'是懶惰的(文檔說'CB.consume'把所有的值都放到內存中)。如何修改你的'sink'函數來簡單地處理每一行(例如,給每行添加一個給定的字符串)? – Chris