csv - 使用 pipes-csv 从 csv 文件中读取第一行

标签 csv haskell haskell-pipes

我正在使用 pipes-csv 库读取一个 csv 文件。我想先读第一行,然后再读其余的。不幸的是,在 Pipes.Prelude.head 函数返回之后。管道正在以某种方式关闭。有没有办法先读取 csv 的头部,然后再读取其余部分。

import qualified Data.Vector as V
import Pipes
import qualified Pipes.Prelude as P
import qualified System.IO as IO
import qualified Pipes.ByteString as PB
import qualified Data.Text as Text
import qualified Pipes.Csv as PCsv
import Control.Monad (forever)

showPipe :: Proxy () (Either String (V.Vector Text.Text)) () String IO b
showPipe = forever $ do
    x::(Either String (V.Vector Text.Text)) <- await
    yield $ show x


main :: IO ()
main = do
  IO.withFile "./test.csv"
              IO.ReadMode
              (\handle -> do
                  let producer = (PCsv.decode PCsv.NoHeader (PB.fromHandle handle))
                  headers <- P.head producer
                  putStrLn "Header"
                  putStrLn $ show headers
                  putStrLn $ "Rows"
                  runEffect ( producer>->
                              (showPipe) >->
                              P.stdoutLn)
               )

如果我们不先读取标题,我们可以毫无问题地读取整个 csv:

main :: IO ()
main = do
  IO.withFile "./test.csv"
              IO.ReadMode
              (\handle -> do
                  let producer = (PCsv.decode PCsv.NoHeader (PB.fromHandle handle))
                  putStrLn $ "Rows"
                  runEffect ( producer>->
                              (showPipe) >->
                              P.stdoutLn)
               )

最佳答案

Pipes.Csv 有处理 header 的 Material ,但我认为这个问题实际上是在寻找更复杂的使用 Pipes.awaitPipes .下一步。第一个下一个:

>>> :t Pipes.next 
Pipes.next :: Monad m => Producer a m r -> m (Either r (a, Producer a m r))

next 是检查生产者的基本方法。它有点像列表上的模式匹配。对于列表,两种可能性是 []x:xs - 这里是 Left ()Right (headers, rows )。后一对是你要找的。当然,需要一个 Action (在 IO 中)才能得到它:

main :: IO ()
main = do
  handle <- IO.openFile  "./test.csv" IO.ReadMode
  let producer :: Producer (V.Vector Text.Text) IO ()
      producer = PCsv.decode PCsv.NoHeader (PB.fromHandle handle)  >-> P.concat
  e <- next producer
  case e of
    Left () -> putStrLn "No lines!"
    Right (headers, rows) -> do
      putStrLn "Header"
      print headers
      putStrLn $ "Rows"
      runEffect ( rows >-> P.print)
  IO.hClose handle

因为 Either 值在这里会让人分心,所以我用 P.concat <消除了 Left 值 - 不解析的行 -/p>

next 不作用于管道内部,而是直接作用于 Producer,它将其视为一种“有效列表”,最后有最终返回值.我们上面得到的特定效果当然可以通过 await 来实现,它在管道内部起作用。我可以用它来拦截管道中出现的第一个项目,基于它做一些 IO,然后转发剩余的元素:

main :: IO ()
main = do
  handle <- IO.openFile  "./grades.csv" IO.ReadMode
  let producer :: Producer (V.Vector Text.Text) IO ()
      producer = PCsv.decode PCsv.NoHeader (PB.fromHandle handle)  >-> P.concat
      handleHeader :: Pipe (V.Vector Text.Text) (V.Vector Text.Text) IO ()
      handleHeader = do
        headers <- await  -- intercept first value
        liftIO $ do       -- use it for IO
          putStrLn "Header"
          print headers
          putStrLn $ "Rows"
        cat               -- pass along all later values
  runEffect (producer >-> handleHeader >-> P.print)
  IO.hClose handle

不同之处在于,如果 producer 为空,我将无法声明它,就像我在前面的程序中使用 No lines! 所做的那样。

顺便说一下,showPipe 可以定义为 P.map show,或者简单地定义为 P.show(但是使用专门的输入您添加的内容。)

关于csv - 使用 pipes-csv 从 csv 文件中读取第一行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41234673/

相关文章:

javascript - 如何在预加载阶段 Phaser.js 中使用 Papa Parse 解析 csv,而不是异步?

arrays - 在 Haskell 中以 O(1) 的时间获取 Ix 范围的中间值

haskell - 如何在 Haskell 中概括从 url 和文件读取

haskell - ProxyFast/ProxyCorrect 的 MonadTransControl 实例

haskell - 在haskell中将管道组合成一个循环或循环

java - 使用 Java 将逗号分隔的 CSV 文件转换为制表符分隔

java - 从 csv 文件加载数据时出现问题 - Java

haskell - 如何检查 BST 是否有效?

json - 使用 Haskell 对巨大的 json 数组进行子采样

csv - 经典 ASP - 如何使用 UTF-8 将数据保存到 CSV 文件