2014-01-21 37 views
2

我目前正在嘗試弄清楚如何在Haskell中列出(gzipped)TAR檔案。 Codec.Archive.Tar似乎是正確的選擇,但我不知道如何mapentryPath超過Entries monoid。在Haskell中列出TAR檔案

我們假設TAR包含條目(僅文件)a.txt, b.txt, c.txt並且名爲foo.tar.gz。這裏是我的代碼來讀取文件:

import qualified Codec.Archive.Tar as Tar 
import qualified Data.ByteString.Lazy as BS 
import qualified Codec.Compression.GZip as GZip 

foldEntryToPath :: Tar.Entry -> [String] -> [String] 
foldEntryToPath entry list = list ++ [show $ Tar.entryPath entry] 

-- Converts TAR errors to a string. 
entryFailMapper :: String -> [String] 
entryFailMapper err = [err] 

main = do 
     fileContent <- fmap GZip.decompress $ BS.readFile "foo.tar.gz" 
     entries <- fmap Tar.read fileContent :: Tar.Entries 
     -- Here I don't know how to correctly apply fmap 
     entryPaths <- Tar.foldEntries foldEntryToPath [] entryFailMapper entries :: [String] 
     -- This should print ["a.txt", "b.txt", "c.txt"] 
     print entryPaths 

這是一個被runghc印刷錯誤:

readtar.hs:14:49: 
Expecting one more argument to `Tar.Entries' 
In an expression type signature: Tar.Entries 
In a stmt of a 'do' block: 
    entries <- fmap Tar.read fileContent :: Tar.Entries 
In the expression: 
    do { fileContent <- fmap GZip.decompress 
         $ BS.readFile "foo.tar.gz"; 
     entries <- fmap Tar.read fileContent :: Tar.Entries; 
     entryPaths <- Tar.foldEntries 
         foldEntryToPath [] (\ x -> [...]) entries :: 
         [String]; 
     print entryPaths } 

到目前爲止,我有哈斯克爾知之甚少,但是通過閱讀the docs我不知道爲什麼Tar.Entries是一個類型類(是否正確的術語,當它說expecting n more arguments to <type>?)或什麼是正確的類型使用。

任何幫助將不勝感激!

+1

注意,這不是LIB的最新版本。 – Vektorweg

+0

@Vektorweg謝謝,我沒有注意到(我更新的鏈接!)。然而,這是隻是文檔鏈接(通過谷歌首先發現他們),我安裝了使用'cabal安裝tar'它實際安裝了0.4.0.1 –

回答

1

有了一點擺弄周圍,我現在有一個完整的工作示例。

其中一個主要問題是Tar.foldEntries的類似foldr的行爲。實際上,我有一個〜25GB的TAR文件,其中包含幾百萬條記錄。有關這是一個壞主意的信息,請參閱the HaskellWiki。 (注:作爲高效的不是這個問題,但我認爲foldEntries - 免費的解決方案是爲這個特定用例更好

因此,我寫我自己的遞歸Tar.Entries -> [String]映射功能,即使錯誤當前沒有處理特別好。 ,它應該提供一個良好的起點。

import qualified Codec.Archive.Tar as Tar 
import qualified Data.ByteString.Lazy as BS 
import qualified Codec.Compression.GZip as GZip 

entriesToPaths :: Tar.Entries Tar.FormatError -> [String] 
entriesToPaths (Tar.Next entry entries) = [Tar.entryPath entry] ++ entriesToPaths entries 
entriesToPaths Tar.Done = [] :: [String] 
entriesToPaths (Tar.Fail e) = ["Error"] 

main = do 
     fileContent <- fmap GZip.decompress $ BS.readFile "foo.tar.gz" 
     let entries = Tar.read fileContent 
     let entryPaths = entriesToPaths entries 
     -- This should print ["a.txt", "b.txt", "c.txt"] 
     print entryPaths 
+0

在這種情況下,我沒有得到你對foldr的負面評論,因爲你的entriesToPaths函數只是一個手寫的foldr。 – kosmikus

+0

@kosmikus我認爲你是對的。我原本以爲我實現了foldl,但事實並非如此。然而,基於foldEntries的解決方案仍然讓我的電腦受到打擊,但它並沒有實現我自己的實現。我會在明天再次檢查你的解決方案,也許這些問題不是由'foldEntries'本身引起的,而是由另一種說法引起的。 –

+0

那麼,在你的問題中,在'foldEntryToPath'中,你將新元素附加到列表的* end *。這永遠不會有效。在這個解決方案中,在'entryToPaths'中,您將新條目附加到開頭。所以這個區別是重要的。不是你是否使用'foldEntries'。 – kosmikus

1

我認爲是固定的foldEntryToPath需求:

foldEntryToPath :: Tar.Entry -> [String] -> [String] 
foldEntryToPath entry list = (show $ Tar.entryPath entry) : list 

而且在main

fileContent <- fmap GZip.decompress $ BS.readFile "foo.tar.gz" 
let entries = Tar.read fileContent 
let entryPaths = Tar.foldEntries foldEntryToPath [] entryFailMapper entries 
print entryPaths 
+0

謝謝你的努力!我得到了我的o wn代碼在你的帖子前幾秒鐘工作。就我所見,隨着您的更改,代碼運行良好,但是在某些情況下,類似foldr的'foldEntries'行爲會出現一些嚴重的性能問題(但我沒有具體要求性能和/或內存效率,所以你的帖子仍然是正確的)。使用'foldEntries'替代我的答案來查看備用解決方案。 –

+0

當我將您的更改應用到問題的代碼中時,第15行出現此錯誤:'無法將類型'Tar.FormatError'與'[Char]'匹配。你能重現這個問題嗎? –