title
約 4500 個の XML (HTML5) ファイルを含むディレクトリがあり、それらのデータ (基本的にはと)の「マニフェスト」を作成したいと考えていますbase/@href
。
この目的のために、関数を使用して関連するすべてのファイル パスを収集し、それらを readFile で開き、tagsoup ベースのパーサーに送信してから、結果のリストを出力/フォーマットしています。
これはファイルのサブセットに対して機能しますが、最終的にopenFile: resource exhausted (Too many open files)
エラーが発生します。少し読んだ後では、これはそれほど驚くべきことではありません。私はこれを使用しmapM parseMetaDataFile files
て、すべてのハンドルをすぐに開きます。
私が理解できないのは、問題を回避する方法です。Iteratee について少し読んでみました。これを Tagsoup で簡単に接続できますか? Strict IO は、とにかく私が使用した方法 (へー) では、ファイルがそれほど大きくなくても (平均で 28 KB)、コンピューターをフリーズさせました。
任意のポインタをいただければ幸いです。大きなリストを作成するアプローチも失敗する可能性があることは理解していますが、4.5k 要素はそれほど長くはありません...また、どこにでもあるはず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.