将文件中的行与从文件名派生的时间戳组合在一起

时间:2014-04-25 18:48:16

标签: haskell conduit

我有一个目录,里面装满了我需要解析和处理的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)))

是否有人会想到一种方法,涉及将包含时间戳的一个管道与另一个包含文件行的管道拉上来?在我提出这个问题之前,这就是我想要做的事情。

1 个答案:

答案 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将该功能提升到管道中。