diff --git a/Data/ByteString/Streaming.hs b/Data/ByteString/Streaming.hs
--- a/Data/ByteString/Streaming.hs
+++ b/Data/ByteString/Streaming.hs
@@ -169,6 +169,7 @@
     -- * Etc.
     , zipWithStream    -- zipWithStream :: Monad m => (forall x. a -> ByteString m x -> ByteString m x) -> [a] -> Stream (ByteString m) m r -> Stream (ByteString m) m r 
     , distribute       -- distribute :: ByteString (t m) a -> t (ByteString m) a 
+
   ) where
 
 import Prelude hiding
@@ -207,6 +208,8 @@
 import Foreign.Ptr
 import Data.Functor.Compose
 import Data.Functor.Sum
+import Control.Monad.Trans.Resource
+
 -- | /O(n)/ Concatenate a stream of byte streams.
 concat :: Monad m => Stream (ByteString m) m r -> ByteString m r
 concat x = destroy x join Go Empty 
@@ -311,9 +314,9 @@
 
 {-| /O(n)/ Convert a monadic byte stream into a single strict 'ByteString',
    retaining the return value of the original pair. This operation is
-   for use with 'mapsM'.
+   for use with 'mapped'.
 
-> mapsM R.toStrict :: Monad m => Stream (ByteString m) m r -> Stream (Of ByteString) m r 
+> mapped R.toStrict :: Monad m => Stream (ByteString m) m r -> Stream (Of ByteString) m r 
  
    It is subject to all the objections one makes to Data.ByteString.Lazy 'toStrict'; 
    all of these are devastating. 
@@ -361,9 +364,9 @@
     followed by the memory of the succession of bytes. 
 
     Because one preserves the return value, @toLazy@ is a suitable argument
-    for 'Streaming.mapsM'
+    for 'Streaming.mapped'
 
->   S.mapsM Q.toLazy :: Stream (ByteString m) m r -> Stream (Of L.ByteString) m r
+>   S.mapped Q.toLazy :: Stream (ByteString m) m r -> Stream (Of L.ByteString) m r
 
 >>> Q.toLazy "hello"
 "hello" :> ()
@@ -410,7 +413,7 @@
 
 -}
 denull :: Monad m => Stream (ByteString m) m r -> Stream (ByteString m) m r 
-denull = hoist (run . maps effects) . separate . mapsM nulls
+denull = hoist (run . maps effects) . separate . mapped nulls
 {-#INLINE denull #-}
 
 {- | /O(1)/ Test whether a ByteString is empty, collecting its return value;
@@ -420,7 +423,7 @@
 False :> ()
 >>> Q.null ""
 True :> ()
->>> S.print $ mapsM R.null $ Q.lines "yours,\nMeredith"
+>>> S.print $ mapped R.null $ Q.lines "yours,\nMeredith"
 False
 False
 
@@ -443,11 +446,11 @@
     There are many ways to remove null bytestrings from a 
     @Stream (ByteString m) m r@ (besides using @denull@). If we pass next to
 
->>> mapsM nulls bs :: Stream (Sum (ByteString m) (ByteString m)) m r
+>>> mapped nulls bs :: Stream (Sum (ByteString m) (ByteString m)) m r
 
     then can then apply @Streaming.separate@ to get
 
->>> separate (mapsM nulls bs) :: Stream (ByteString m) (Stream (ByteString m) m) r
+>>> separate (mapped nulls bs) :: Stream (ByteString m) (Stream (ByteString m) m) r
 
     The inner monad is now made of the empty bytestrings; we act on this 
     with @hoist@ , considering that 
@@ -458,7 +461,7 @@
 
     we have 
 
->>> hoist (Q.effects . Q.concat) . separate . mapsM Q.nulls
+>>> hoist (Q.effects . Q.concat) . separate . mapped Q.nulls
   :: Monad n =>  Stream (Q.ByteString n) n b -> Stream (Q.ByteString n) n b
 
 
@@ -483,7 +486,7 @@
 
 >>> Q.length "one\ntwo\three\nfour\nfive\n"
 23 :> ()
->>> S.print $ S.take 3 $ mapsM Q.length $ Q.lines "one\ntwo\three\nfour\nfive\n" 
+>>> S.print $ S.take 3 $ mapped Q.length $ Q.lines "one\ntwo\three\nfour\nfive\n" 
 3
 8
 4
@@ -1104,16 +1107,19 @@
   where 
 -- comb :: [P.ByteString] -> [P.ByteString] -> ByteString -> [ByteString]
 --  comb acc (s:[]) (Empty r)    = Step (revChunks (s:acc) (Return r))
-  comb acc [s] (Empty r)    = Step $ L.foldl' (flip Chunk) 
-                                              (Empty (Return r)) 
-                                              (s:acc) 
-  comb acc [s] (Chunk c cs) = comb (s:acc) (S.splitWith p c) cs
-  comb acc b (Go m)         = Effect (liftM (comb acc b) m)
-  comb acc (s:ss) cs        = Step $ L.foldl' (flip Chunk)  
-                                              (Empty (comb [] ss cs)) 
-                                              (s:acc)
-                                              
---  comb acc (s:ss) cs           = Step (revChunks (s:acc) (comb [] ss cs))
+  comb acc [s]    (Empty r)    = Step $ L.foldl' (flip Chunk) 
+                                                 (Empty (Return r)) 
+                                                 (s:acc) 
+  comb acc [s]    (Chunk c cs) = comb (s:acc) (S.splitWith p c) cs
+  comb acc b      (Go m)       = Effect (liftM (comb acc b) m)
+  comb acc (s:ss) cs           = Step $ L.foldl' (flip Chunk)  
+                                                 (Empty (comb [] ss cs)) 
+                                                 (s:acc)
+  comb acc []  (Empty r)    = Step $ L.foldl' (flip Chunk) 
+                                                 (Empty (Return r)) 
+                                                 acc 
+  comb acc []  (Chunk c cs) = comb acc (S.splitWith p c) cs                             
+ --  comb acc (s:ss) cs           = Step (revChunks (s:acc) (comb [] ss cs))
 
 {-# INLINABLE splitWith #-}
 
@@ -1469,29 +1475,67 @@
 hGetNonBlocking = hGetNonBlockingN defaultChunkSize
 {-#INLINE hGetNonBlocking #-}
 
--- | Read an entire file into a chunked 'ByteString IO ()'.
--- The Handle will be held open until EOF is encountered.
---
-readFile ::  MonadIO m => FilePath -> ByteString m ()
-readFile f = Go $ liftM hGetContents (liftIO (openBinaryFile f ReadMode))
-{-#INLINE readFile #-}
+{-| Write a 'ByteString' to a file. Use 'Control.Monad.Trans.ResourceT.runResourceT'
+    to ensure that the handle is closed. 
 
--- | Write a 'ByteString' to a file.
---
-writeFile :: FilePath -> ByteString IO r -> IO r
-writeFile f txt = bracket
-    (openBinaryFile f WriteMode)
-    hClose
-    (\hdl -> hPut hdl txt)
+>>> :set -XOverloadedStrings
+>>> runResourceT $ Q.writeFile "hello.txt" "Hello world.\nGoodbye world.\n" 
+>>> :! cat "hello.txt"
+Hello world.
+Goodbye world.
+>>> runResourceT $ Q.writeFile "hello2.txt" $ Q.readFile "hello.txt"
+>>> :! cat hello2.txt 
+Hello world.
+Goodbye world.
+
+ -}
+writeFile :: MonadResource m => FilePath -> ByteString m r -> m r
+writeFile f str = do
+  (key, handle) <- allocate (openBinaryFile f WriteMode) hClose
+  r <- hPut handle str
+  release key
+  return r
 {-# INLINE writeFile #-}
 
--- | Append a 'ByteString' to a file.
---
-appendFile :: FilePath -> ByteString IO r -> IO r
-appendFile f txt = bracket
-    (openBinaryFile f AppendMode)
-    hClose
-    (\hdl -> hPut hdl txt)
+{-| Read an entire file into a chunked 'ByteString IO ()'.
+    The Handle will be held open until EOF is encountered.
+    The block governed by 'Control.Monad.Trans.Resource.runResourceT'
+    will end with the closing of any handles opened.
+
+>>> :! cat hello.txt
+Hello world.
+Goodbye world. 
+>>> runResourceT $ Q.stdout $ Q.readFile "hello.txt"
+Hello world.
+Goodbye world. 
+  -}
+
+readFile :: MonadResource m => FilePath -> ByteString m ()
+readFile f = bracketByteString (openBinaryFile f ReadMode) hClose hGetContents
+{-#INLINE readFile #-}
+
+
+
+{-| Append a 'ByteString' to a file. Use 'Control.Monad.Trans.ResourceT.runResourceT'
+    to ensure that the handle is closed. 
+
+>>> runResourceT $ Q.writeFile "hello.txt" "Hello world.\nGoodbye world.\n"
+>>> runResourceT $ Q.stdout $ Q.readFile "hello.txt"
+Hello world.
+Goodbye world.
+>>> runResourceT $ Q.appendFile "hello.txt" "sincerely yours,\nArthur\n"
+>>> runResourceT $ Q.stdout $  Q.readFile "hello.txt"
+Hello world.
+Goodbye world.
+sincerely yours,
+Arthur
+  -}
+appendFile :: MonadResource m => FilePath -> ByteString m r -> m r
+appendFile f str = do
+  (key, handle) <- allocate (openBinaryFile f AppendMode) hClose
+  r <- hPut handle str
+  release key
+  return r
 {-# INLINE appendFile #-}
 
 -- | getContents. Equivalent to hGetContents stdin. Will read /lazily/
diff --git a/Data/ByteString/Streaming/Char8.hs b/Data/ByteString/Streaming/Char8.hs
--- a/Data/ByteString/Streaming/Char8.hs
+++ b/Data/ByteString/Streaming/Char8.hs
@@ -216,7 +216,7 @@
 -- | /O(n)/ Convert a stream of separate characters into a packed byte stream.
 pack :: Monad m => Stream (Of Char) m r -> ByteString m r
 pack  = fromChunks 
-        . mapsM (liftM (\(str :> r) -> Char8.pack str :> r) . S.toList) 
+        . mapped (liftM (\(str :> r) -> Char8.pack str :> r) . S.toList) 
         . chunksOf 32 
 {-# INLINABLE pack #-}
 
@@ -502,7 +502,7 @@
 --   the genuinely streaming 'words'. A function that returns individual
 --   strict bytestrings would concatenate even infinitely
 --   long words like @cycle "y"@ in memory. It is best for the user who
---   has reflected on her materials to write `mapsM toStrict . words` or the like,
+--   has reflected on her materials to write `mapped toStrict . words` or the like,
 --   if strict bytestrings are needed.
 words :: Monad m => ByteString m r -> Stream (ByteString m) m r
 words =  filtered . R.splitWith B.isSpaceWord8 
diff --git a/Data/ByteString/Streaming/Internal.hs b/Data/ByteString/Streaming/Internal.hs
--- a/Data/ByteString/Streaming/Internal.hs
+++ b/Data/ByteString/Streaming/Internal.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE CPP, BangPatterns #-}
-{-#LANGUAGE RankNTypes, GADTs #-}
+{-# LANGUAGE CPP, BangPatterns, RankNTypes, GADTs #-}
 {-# LANGUAGE UnliftedFFITypes, MagicHash, UnboxedTuples #-}
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-} 
+-- for resourcet etc.
 module Data.ByteString.Streaming.Internal (
    ByteString (..) 
    , consChunk             -- :: S.ByteString -> ByteString m r -> ByteString m r
@@ -26,6 +27,9 @@
    , reread
    , inlinePerformIO
    , unsafeLast
+   
+   -- * ResourceT help
+   , bracketByteString
   ) where
 
 import Prelude hiding
@@ -60,6 +64,9 @@
 import GHC.Base                 (realWorld#,unsafeChr)
 import GHC.IO                   (IO(IO))
 
+import Control.Monad.Base
+import Control.Monad.Trans.Resource
+import Control.Monad.Catch (MonadCatch (..))
 -- | A space-efficient representation of a succession of 'Word8' vectors, supporting many
 -- efficient operations.
 --
@@ -133,9 +140,45 @@
   {-# INLINE mempty #-}
   mappend = liftM2 mappend
   {-# INLINE mappend #-}
-      
--- data Word8_ r = Word8_ {-#UNPACK#-} !Word8 r 
--- This might be preferable to (Of Word8 r), but the present approach is simpler.
+
+instance (MonadBase b m) => MonadBase b (ByteString m) where
+  liftBase  = mwrap . fmap return . liftBase
+  {-#INLINE liftBase #-}
+
+instance (MonadThrow m) => MonadThrow (ByteString m) where
+  throwM = lift . throwM 
+  {-#INLINE throwM #-}
+
+
+instance (MonadCatch m) => MonadCatch (ByteString m) where
+  catch str f = go str
+    where
+    go p = case p of
+      Chunk bs rest  -> Chunk bs (go rest)
+      Empty  r       -> Empty r
+      Go  m          -> Go (catch (do
+          p' <- m
+          return (go p'))  
+       (\e -> return (f e)) )
+  {-#INLINABLE catch #-}
+     
+instance (MonadResource m) => MonadResource (ByteString m) where
+  liftResourceT = lift . liftResourceT
+  {-#INLINE liftResourceT #-}
+
+bracketByteString :: (MonadResource m) =>
+       IO a -> (a -> IO ()) -> (a -> ByteString m b) -> ByteString m b
+bracketByteString alloc free inside = do
+        (key, seed) <- lift (allocate alloc free)
+        clean key (inside seed)
+  where
+    clean key = loop where
+      loop str = case str of 
+        Empty r        -> Go (release key >> return (Empty r))
+        Go m           -> Go (liftM loop m)
+        Chunk bs rest  -> Chunk bs (loop rest)
+{-#INLINABLE bracketByteString #-}
+
 
 data SPEC = SPEC | SPEC2
 {-# ANN type SPEC ForceSpecConstr #-}
diff --git a/streaming-bytestring.cabal b/streaming-bytestring.cabal
--- a/streaming-bytestring.cabal
+++ b/streaming-bytestring.cabal
@@ -1,5 +1,5 @@
 name:                streaming-bytestring
-version:             0.1.2.2
+version:             0.1.3.0
 synopsis:            effectful byte steams, or: bytestring io done right.
 
 description:         This is an implementation of effectful, memory-constrained 
@@ -189,7 +189,10 @@
                      , mtl >=2.1 && <2.3
                      , mmorph >=1.0 && <1.2
                      , transformers >=0.3 && <0.5
-                     , streaming >  0.1.2.0 && < 0.1.2.4
+                     , transformers-base
+                     , streaming >=  0.1.3.0 && <= 0.1.3.5
+                     , resourcet
+                     , exceptions
   if impl(ghc < 7.8) 
     build-depends:
                      bytestring < 0.10.4.0
