2013-11-21 13 views
5

Khi tiêu đề cho biết, tôi muốn đọc các dòng từ một tệp nằm bên trong kho lưu trữ zip, sử dụng đường dẫn zip (tệp zip Tôi đang xử lý là rất lớn, vì vậy tôi cần để có thể làm điều này trong bộ nhớ liên tục). Tôi mò mẫm ý tưởng rất cơ bản về ống dẫn, nhưng chưa bao giờ sử dụng chúng trong sự tức giận, và tôi cảm thấy khá khó khăn khi bắt đầu từ đâu. Tôi đã đọc hướng dẫn ống dẫn, nhưng tôi gặp khó khăn khi kết hợp với vấn đề của tôi.Đọc các dòng từ một tệp bên trong kho lưu trữ zip bằng cách sử dụng mã bưu điện của Haskell

Các tài liệu zip-ống dẫn nói người ta có thể nguồn từ một kho lưu trữ zip qua giống như sau:

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

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

Tôi đoán những gì tôi cần làm là viết một cái gì đó ở vị trí của CB.sinkFile. Data.Conduit.Text có chức năng lines - điều này có thể được sử dụng theo cách nào đó để lấy các dòng ra khỏi tệp không?

Tôi thực sự đánh giá cao một ví dụ đơn giản, giả sử sử dụng putStrLn để viết ra các dòng của tệp văn bản đơn giản được lưu trữ bên trong tệp zip. Cảm ơn trước.

Trả lời

6

câu trả lời của Michael nhưng với 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

Cảm ơn rất nhiều, điều này có ý nghĩa hơn nhiều. Sử dụng ống dẫn đã làm cho mã của tôi sạch hơn nhiều. – Chris

1

Dưới đây là một ví dụ đơn giản:

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) 

Bạn cũng có thể view and experiment on FP Haskell Center.

+1

Cảm ơn đã dành thời gian để trả lời, Michael. Ví dụ của bạn thể hiện việc sử dụng chung các ống dẫn (mà tôi hiểu từ hướng dẫn đường ống dẫn), nhưng không minh họa cách người ta sử dụng ống dẫn dây như được nêu trong câu hỏi của tôi, và tôi sợ tôi quá ngu ngốc để nhảy ngay lập tức từ ví dụ của bạn đến một giải pháp. Trợ giúp thêm thực sự sẽ được đánh giá cao! – Chris

+0

Ví dụ không hoạt động: nhận được "Biến không nằm trong phạm vi: chính :: [GHC.Types.Char] -> t" – Christophe

1

Đây là một example- đơn giản

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 

Bạn có thể xử lý dữ liệu vì nó đi qua trong hàm chìm (tiêu thụ như mong muốn bằng CL, chức năng CB), hoặc kể từ khi dữ liệu đang được trả lại uể oải , bạn có thể sửa đổi dữ liệu trong res.

+0

Cảm ơn vì điều này, @jamshidh. Nhưng, chính xác thì tôi sẽ xử lý mọi thứ trong chức năng bồn rửa như thế nào? Nếu tôi chuyển đổi 'res' thành một danh sách các chuỗi, và xử lý chúng, tôi thấy rằng có ít thành phần trong danh sách này hơn là có. Số lượng các mục dường như bị giới hạn bởi bộ nhớ mà chúng yêu cầu. Tôi không chắc 'res' là lười (tài liệu nói rằng' CB.consume' đặt tất cả các giá trị vào bộ nhớ). Làm thế nào để sửa đổi chức năng 'sink' của bạn để xử lý trivially mỗi dòng (ví dụ, nối thêm một chuỗi cho trước vào mỗi dòng)? – Chris

Các vấn đề liên quan