Сценарий : у меня есть текстовый файл ~ 900 МБ, который отформатирован следующим образом
...
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
.
Я просто не могу понять это, и мне действительно нужен намек.
Заранее большое спасибо.