Q:

What is the Haskell idiom for walking a file and filling a structure when only some of the data is interesting? 

Often I find I need to parse a little bit of text.  Usually the text is not lines of uniform data like CSV rather it is more unstructured.  So the goal is not to turn each line into a Haskell data type but to gather up data into a structure. 
In an imperative language I would write something like this. 
values = {}  # could just as easily be a class or C struct

for line in input_lines:
    if line matches A:
        parse out interesting piece
        values[A] = parsed chunk
    elif line matches B:
        parse out interesting piece
        values[B] = parsed chunk
    ...
    elif line matches Z:
        parse out interesting piece
        values[Z] = parsed chunk
        break  # we know there is nothing else after this

do something with values

I wrote a bit of Haskell this morning to do the same thing using foldr. 
This parses the output of rsync --stats.  A sample file looks like this. 
Number of files: 1
Number of files transferred: 0
Total file size: 4953701 bytes
Total transferred file size: 0 bytes
Literal data: 10 bytes
Matched data: 230 bytes
File list size: 43
File list generation time: 0.001 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 11
Total bytes received: 57

sent 11 bytes  received 57 bytes  12.36 bytes/sec
total size is 4953701  speedup is 72848.54

Small and simple to demonstrate my problem.  This particular file format is representative of this recurring style of problem where I want to quickly read 3 or 5 bits from a file and doing something else with the results.  In an imperative language I'd just toss them into a few variables, a dictionary, something.  The Haskell below is my attempt at a similar approach. 
{-# LANGUAGE OverloadedStrings #-}

import qualified Data. Map as M
import qualified Data. Text as T
import Data. Text (Text)
import qualified Data. Text. IO as TIO
import Data. Text. Read (decimal)
import System. Environment (getArgs)

stats_map :: M.Map Text Int
stats_map = foldr (uncurry M.insert) M.empty [("Total file size", 1),
                                              ("Literal data", 2),
                                              ("Matched data", 3)]

getStatsMap :: Text -> M.Map Text Integer -> M.Map Text Integer
getStatsMap t rm = doMatch chunks rm
  where
    chunks = [ T.strip chunk | chunk <- T.splitOn ":" t ]

  doMatch :: [Text] -> M.Map Text Integer -> M.Map Text Integer
  doMatch (f1:f2:_) rm' =
    case M.lookup f1 stats_map of
      (Just _) -> case decimal .  head .  T.words $ f2 of
                    Left _      -> rm'
                    Right (x,_) -> M.insert f1 x rm'
      Nothing  -> rm'
  doMatch _ rm' = rm'

parseStats :: [Text] -> M.Map Text Integer
parseStats ts = foldr getStatsMap M.empty ts

readStats :: FilePath -> IO [Text]
readStats filename = TIO.readFile filename >>= return .  T.lines

main :: IO ()
main = do
  [filename] <- getArgs
  lines <- readStats filename
  putStrLn .  show .  parseStats $ lines

Unlike in the imperative version I cannot break the foldr execution though. 
Laziness cannot rescue me here.  Parsec, attoparsec and friends are both overkill and not exactly what I am looking for this kind of task. 
How can I approach this common imperative task in a more Haskell way? 

A:

I've gone for simple data structures to try to emphasise that the behaviour's there in the standard ones if you want it:
First version - using catMaybes and take to ignore irrelevant data and shortcut:
import Data. Maybe (catMaybes)
import Data. Char (isDigit)
import Control. Monad (msum)

-- maybe get an int if the key matches before :

get :: String -> String -> Maybe Int
get key input = let (l,r) = break (==':') input in
                if l == key then Just .  read .  filter isDigit $ r
                            else Nothing

-- get any that match

getAny :: [String] -> String -> Maybe Int
getAny keys input =  msum $ map (flip get input) keys

-- get all that match at least one

getThese :: [String] -> String -> [Int]
getThese keys = take (length keys) .  catMaybes .  map (getAny keys) .  lines

This gives you the output you were after:
fmap (getThese ["Total file size","Literal data","Matched data"]) (readFile "example.txt")  >>= print
[4953701,10,230]

and we can check that it's shortcutting by feeding it a bomb to eat:
> getThese ["a"] (unlines ["no","a: 5",undefined])
[5]

Sometimes recursion is simpler
Pick out one element for each predicate in order:
oneEach :: [(a->Bool)] -> [a] -> [a]
oneEach [] _ = []
oneEach _ [] = error "oneEach: run out of input while still looking"
oneEach qs@(p:ps) (i:is) | p i   = i : oneEach ps is
                         | otherwise = oneEach qs is

Compose some functions to split the string and pull out the ones we wanted, then read the data.  This assumes you want all the digits to the right of the : as your Int
getInOrder :: [String] -> String -> [Int]
getInOrder keys = map (read.filter isDigit.snd)
                 .  oneEach (map ((.fst).(==)) keys)
                 .  map (break (==':'))
                 .  lines

which works:
main = fmap (getInOrder ["Total file size","Literal data","Matched data"]) (readFile "example.txt")  >>= print
[4953701,10,230]

