使用 Haskell 的 zip-conduit 从 zip 存档中的文件中读取行
Posted
技术标签:
【中文标题】使用 Haskell 的 zip-conduit 从 zip 存档中的文件中读取行【英文标题】:Read lines from a file inside a zip archive using Haskell's zip-conduit 【发布时间】:2013-11-21 17:01:28 【问题描述】:正如标题所说,我希望能够使用 zip-conduit 从 zip 存档中的文件中读取行(我正在处理的 zip 文件非常大,所以我需要能够在不断的记忆中做到这一点)。我理解了管道的基本概念,但从来没有在愤怒中使用过它们,并且对于从哪里开始感到很困惑。我已经阅读了管道教程,但我无法将其与我的问题相匹配。
zip-conduit 文档说可以通过以下方式从 zip 存档中获取资源:
import qualified Data.Conduit.Binary as CB
import Codec.Archive.Zip
withArchive archivePath $ do
name:_ <- entryNames
sourceEntry name $ CB.sinkFile name
我想我需要做的是写一些东西来代替CB.sinkFile
。 Data.Conduit.Text
有一个 lines
函数——它可以以某种方式用于从文件中取出行吗?
我非常感谢一个简单的例子,比如使用putStrLn
写出一个简单的文本文件的行,该文件被归档在一个 zip 文件中。提前致谢。
【问题讨论】:
【参考方案1】:迈克尔的回答,但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)
【讨论】:
非常感谢,这更有意义。使用导管使我的代码更加简洁。【参考方案2】:这是一个简单的例子:
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)
你也可以view and experiment on FP Haskell Center。
【讨论】:
感谢您抽出宝贵时间回复,迈克尔。您的示例演示了导管的一般用途(我从导管教程中了解到),但没有说明如何使用我的问题中概述的 zip-conduit,恐怕我太笨了,无法立即跳转从您的示例到解决方案。进一步的帮助真的很感激! 示例不起作用:获取“变量不在范围内:main :: [GHC.Types.Char] -> t”【参考方案3】:这是一个简单的例子-
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
您可以在接收器函数中处理数据(使用 CL、CB 函数根据需要使用),或者由于数据是延迟返回的,您可以在 res 中修改数据。
【讨论】:
谢谢你,@jamshidh。但是,我将如何在 sink 函数中处理事情呢?如果我将res
转换为字符串列表并处理它们,我会发现该列表中的元素数量远远少于应有的数量。项目的数量似乎受到它们所需的内存的限制。我不确定res
是懒惰的(文档说CB.consume
将所有值放入内存)。如何修改您的 sink
函数以轻松处理每一行(例如,将给定的字符串附加到每一行)?以上是关于使用 Haskell 的 zip-conduit 从 zip 存档中的文件中读取行的主要内容,如果未能解决你的问题,请参考以下文章