Si vous utilisez chaîne IO, vous pouvez effectuer les opérations suivantes:
import System.IO
import Control.Monad
-- | Process 100 lines
process100 :: [String] -> MyData
-- whatever this function does
loop :: [String] -> [MyData]
loop lns = go [] lns
where
go acc [] = reverse acc
go acc lns = let (this, next) = splitAt 100 lns in go (process100 this:acc) next
processFile :: FilePath -> IO [MyData]
processFile f = withFile f ReadMode (fmap (loop . lines) . hGetContents)
Notez que cette fonction traitera silencieusement le dernier morceau, même si ce ne sont pas exactement 100 lignes.
paquets comme bytestring et texte fournissent généralement des fonctions comme lines
et hGetContents
donc vous devriez être en mesure d'adapter facilement cette fonction à l'un d'eux.
Il est important de savoir ce que vous faites avec les résultats du traitement de chaque tranche, car vous ne voulez pas conserver ces données plus longtemps que nécessaire. Idéalement, après avoir calculé chaque tranche, les données seraient entièrement consommées et pourraient être gcées. Généralement, soit les résultats séparés sont combinés en une structure de données unique (un "pli"), soit chacun est traité séparément (peut-être en sortie une ligne vers un fichier ou quelque chose de similaire). Si c'est un pli, vous devriez changer « boucle » pour ressembler à ceci:
loopFold :: [String] -> MyData -- assuming there is a Monoid instance for MyData
loopFold lns = go mzero lns
where
go !acc [] = acc
go !acc lns = let (this, next) = splitAt 100 lns in go (process100 this `mappend` acc) next
La fonction loopFold
utilise des modèles bang (activé avec « LANGUE BangPatterns » pragma) pour forcer l'évaluation de la « MyData ». En fonction de ce que MyData est, vous devrez peut-être utiliser deepseq
pour vous assurer qu'il est entièrement évalué.
Si vous écrivez au lieu chaque ligne de sortie, laisser loop
tel qu'il est et changer processFile
:
processFileMapping :: FilePath -> IO()
processFileMapping f = withFile f ReadMode pf
where
pf = mapM_ (putStrLn . show) <=< fmap (loop . lines) . hGetContents
Si vous êtes intéressé par le traitement de style recenseur/iteratee, cela est un problème assez simple. Je ne peux pas donner un bon exemple sans savoir quel type de travail fait process100
, mais cela impliquerait enumLines
et take
.
Est-il nécessaire de traiter exactement 100 lignes à la fois, ou voulez-vous juste traiter en morceaux pour plus d'efficacité? Si c'est le dernier, ne vous inquiétez pas à ce sujet. Il vaut probablement mieux traiter une ligne à la fois, en utilisant une fonction de pli réelle ou une fonction similaire à processFileMapping.
Qu'est-ce qu'un "Mo"? – jrockway
millions d'objets? – kennytm
C'est l'équivalent français de "MB" - méga-octet. – Chuck