У меня есть каталог с примерно 4500 XML (HTML5) файлами, и я хочу создать «манифест» их данных (по существу title
и base/@href
).
С этой целью яиспользовал функцию для сбора всех соответствующих путей к файлам, открывая их с помощью readFile, отправляя их в анализатор на основе tagoup, а затем выводя / форматируя результирующий список.
Это работает для подмножества файлов,но в итоге сталкивается с ошибкой openFile: resource exhausted (Too many open files)
.После некоторого чтения, это не так удивительно: я использую mapM parseMetaDataFile files
, который сразу открывает все ручки.
Что я не могу понять, так это как обойти проблему.Я попытался прочитать немного о Iteratee;Могу ли я легко связать это с Tagsoup?Строгий ввод-вывод, так как я все равно его использовал (хе), заморозил мой компьютер, хотя файлы не очень большие (в среднем 28 КБ).
Любые указатели будут очень благодарны.Я понимаю, что подход к созданию большого списка также может потерпеть неудачу, но элементы размером 4,5 тыс. Не такие длинные ... Кроме того, вероятно, должно быть меньше String
и больше ByteString
везде.
Вотнекоторый код.Прошу прощения за наивность:
import System.FilePath
import Text.HTML.TagSoup
data MetaData = MetaData String String deriving (Show, Eq)
-- | Given HTML input, produces a MetaData structure of its essentials.
-- Should obviously account for errors, but simplified here.
readMetaData :: String -> MetaData
readMetaData input = MetaData title base
where
title =
innerText $
(takeWhile (~/= TagClose "title") . dropWhile (~/= TagOpen "title" []))
tags
base = fromAttrib "href" $ head $ dropWhile (~/= TagOpen "base" []) tags
tags = parseTags input
-- | Parses MetaData from a file.
parseMetaDataFile :: FilePath -> IO MetaData
parseMetaDataFile path = fmap readMetaData $ readFile path
-- | From a given root, gets the FilePaths of the files we are interested in.
-- Not implemented here.
getHtmlFilePaths :: FilePath -> IO [FilePath]
getHtmlFilePaths root = undefined
main :: IO
main = do
-- Will call openFile for every file, which gives too many open files.
metas <- mapM parseMetaDataFile =<< getHtmlFilePaths
-- Do stuff with metas, which will cause files to actually be read.