2014-04-25 35 views
2

我有一個目錄完整的CSV轉儲文件,我需要解析和處理。每個文件名都包含一個我知道如何提取的時間戳。然後我需要處理轉儲中的所有行,但是對於每一行我都需要知道它來自哪個文件時間戳。我可以分別獲取時間戳,並且可以單獨從文件中獲取所有行(以下文件爲How do I implement `cat` in Haskell?),但無法找到合併它們的方法。有任何想法嗎?結合文件中的行與時間戳文件名

{-# LANGUAGE OverloadedStrings #-} 
module Main (main) where 

import Control.Monad.Trans.Resource (MonadResource, runResourceT) 
import Data.Conduit (($=), ($$)) 
import qualified Data.Conduit as C (Conduit, awaitForever) 
import qualified Data.Conduit.Binary as C (sinkHandle, sourceFile) 
import qualified Data.Conduit.Combinators as C (map, sourceDirectory, unlines) 
import qualified Data.Conduit.Text as C (decode, encode, utf8) 
import Data.Text (Text, pack) 
import Data.Time (LocalTime) 
import Filesystem.Path.CurrentOS (FilePath) 
import System.IO (stdout) 
import Prelude hiding (FilePath) 

decodeFilePath :: FilePath -> Text 
decodeFilePath = undefined 

decodeFilePathToString :: FilePath -> String 
decodeFilePathToString = undefined 

extractTimestamp :: Text -> LocalTime 
extractTimestamp = undefined 

readFileConduit :: MonadResource m => C.Conduit FilePath m Text 
readFileConduit = 
    C.awaitForever (\fp -> C.sourceFile (decodeFilePathToString fp) $= C.decode C.utf8) 

readFileWithTimestampConduit :: MonadResource m => C.Conduit FilePath m (LocalTime, Text) 
readFileWithTImestampConduit = ??? 

main :: IO() 
main = do 
    runResourceT $ 
    C.sourceDirectory "data/dumps" $= 
    C.map (pack . show . extractTimestamp . decodeFilePath) $= 
    C.unlines $= 
    C.encode C.utf8 $$ 
    C.sinkHandle stdout 
    runResourceT $ 
    C.sourceDirectory "data/dumps" $= 
    readFileConduit $= 
    C.unlines $= 
    C.encode C.utf8 $$ 
    C.sinkHandle stdout 

編輯:感謝acomar,我有這樣的解決方案:

readFileWithTimestampConduit :: MonadResource m => C.Conduit FilePath m (LocalTime, Text) 
readFileWithTimestampConduit = 
    C.awaitForever (\fp -> 
    C.sourceFile (decodeFilePathToString fp) $= 
    C.decode C.utf8 $= 
    C.linesUnbounded $= 
    C.map (\t -> (extractTimestamp $ decodeFilePath fp, t))) 

有人能想出涉及含有從文件中的行另一個管道拉上了包含時間戳的一個導管的方法嗎?這是我在問這個問題之前想要做的。

+0

你不能只寫兩個?對readFileConduit執行相同的操作,但也將文件句柄傳遞給extractTimestamp。然後返回這對。 – acomar

+0

感謝您的想法。我專注於分別製作時間戳和文件行,然後以某種方式將它們壓縮在一起,除非我無法弄清楚。用解決方案更新了問題。 –

回答

1

回答到更新的問題:

這不會因爲管道是如何設置工作得很好。請注意,輸入類型的管道固定接收單個值:

MonadResource m => C.Conduit i m o 

如果你想利用多個輸入,你有權要求他們爲一對

MonadResource m => C.Conduit (i1, i2) m o 

但是,得到管理它的輸入,你已經寫了你現有的解決方案!另一方面,如果有一種方法可以將導管制作成箭頭,那麼可以毫不費力地完成(***)函數,該函數完全符合您的要求 - 即將兩個輸入箭頭組合起來以生成作用於這一對的箭頭。我的理解是,把管道變成箭頭並不是一個好方法。但是,如果您將readFileConduit降級爲readFile(使用HandlehGetContents),則可以在IO monad內部編寫extractTimeStampreadFile

do let timestamp = extractTimeStamp <..args..> 
    contents <- readFile <..args..> 
    return (timestamp, contents) 

然後,您可以使用簡單的lift將該功能提升到導管中。