【发布时间】:2019-06-05 11:21:36
【问题描述】:
场景:我有一个约 900mb 的文本文件,其格式如下
...
Id: 109101
ASIN: 0806978473
title: The Beginner's Guide to Tai Chi
group: Book
salesrank: 672264
similar: 0
categories: 3
|Books[283155]|Subjects[1000]|Sports[26]|Individual Sports[16533]|Martial Arts[16571]|General[16575]
|Books[283155]|Subjects[1000]|Sports[26]|Individual Sports[16533]|Martial Arts[16571]|Taichi[16583]
|Books[283155]|Subjects[1000]|Sports[26]|General[11086921]
reviews: total: 2 downloaded: 2 avg rating: 5
2000-4-4 cutomer: A191SV1V1MK490 rating: 5 votes: 0 helpful: 0
2004-7-10 cutomer: AVXBUEPNVLZVC rating: 5 votes: 0 helpful: 0
(----- empty line ------)
Id :
并想从中解析信息。
问题:作为第一步(因为我需要它用于另一个上下文)我想逐行处理文件,然后将属于一个产品的“块”收集在一起,然后处理它们与其他逻辑分开。
所以计划如下:
- 定义代表文本文件的源
- 定义一个管道 (?),每个管道从该源取一条线,然后...
- ... 将其传递给其他一些组件。
现在,我正在尝试修改以下示例:
doStuff = do
writeFile "input.txt" "This is a \n test." -- Filepath -> String -> IO ()
runConduitRes -- m r
$ sourceFileBS "input.txt" -- ConduitT i ByteString m () -- by "chunk"
.| sinkFile "output.txt" -- FilePath -> ConduitT ByteString o m ()
readFile "output.txt"
>>= putStrLn
所以sourceFileBS "input.txt" 是ConduitT i ByteString m () 类型,即具有
- 输入类型
i - 输出类型
ByteStream - 单子类型
t - 结果类型
()。
sinkFile 将所有传入数据流式传输到给定文件中。 sinkFile "output.txt" 是输入类型为ByteStream 的管道。
我现在想要的是逐行处理输入源,即每个下游只传递一行。在伪代码中:
sourceFile "input.txt"
splitIntoLines
yieldMany (?)
other stuff
我该怎么做?
我目前拥有的是
copyFile = do
writeFile "input.txt" "This is a \n test." -- Filepath -> String -> IO ()
runConduitRes -- m r
(lineC $ sourceFileBS "input.txt") -- ConduitT i ByteString m () -- by "chunk"
.| sinkFile "output.txt" -- FilePath -> ConduitT ByteString o m ()
readFile "output.txt"
>>= putStrLn --
但这会产生以下类型错误:
* Couldn't match type `bytestring-0.10.8.2:Data.ByteString.Internal.ByteString'
with `Void'
Expected type: ConduitT
()
Void
(ResourceT
(ConduitT
a0 bytestring-0.10.8.2:Data.ByteString.Internal.ByteString m0))
()
Actual type: ConduitT
()
bytestring-0.10.8.2:Data.ByteString.Internal.ByteString
(ResourceT
(ConduitT
a0 bytestring-0.10.8.2:Data.ByteString.Internal.ByteString m0))
()
* In the first argument of `runConduitRes', namely
`(lineC $ sourceFileBS "input.txt")'
In the first argument of `(.|)', namely
`runConduitRes (lineC $ sourceFileBS "input.txt")'
In a stmt of a 'do' block:
runConduitRes (lineC $ sourceFileBS "input.txt")
.| sinkFile "output.txt"
|
28 | (lineC $ sourceFileBS "input.txt") -- ConduitT i ByteString m () -- by "chunk"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
这让我相信现在的问题是第一个管道没有与runConduitRes兼容的输入类型。
我只是无法理解它,真的需要一个提示。
非常感谢。
【问题讨论】:
-
提示:不要只是告诉我们您遇到了类型错误。报告类型错误。请在上面的部分中,而不是 cmets 部分。
-
当然。我编辑了帖子。
-
我不确定,但请尝试
runConduitRes $ (lineC $ ...) .| ...。否则,您将两个参数传递给runConduitRes,第一个是函数lineC。 -
谢谢,这看起来很合理,但还没有完全解决我的问题。我已经编辑了我的帖子。
-
@ngmir 在您编辑的示例中,您有
runConduitRes (lineC $ sourceFileBS "input.txt") .| sinkFile "output.txt"。我认为您可能在runConduitRes之后缺少$:否则您将尝试运行(lineC $ sourceFileBS "input.txt")而不是整个管道。