diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,8 @@
+Quiver combinators for bytestring streaming
+===========================================
+
+    Copyright © 2015 Patryk Zadarnowski «pat@jantar.org».
+    All rights reserved.
+
+This library provides a set of combinators for efficient
+streaming of bytestring data in the Quiver framework.
diff --git a/quiver-bytestring.cabal b/quiver-bytestring.cabal
--- a/quiver-bytestring.cabal
+++ b/quiver-bytestring.cabal
@@ -1,43 +1,39 @@
-name:           quiver-bytestring
-version:        0.0.0.2
-synopsis:       Quiver combinators for bytestring streaming
-homepage:       https://github.com/zadarnowski/quiver-bytestring
-category:       Control
-stability:      alpha
-
-author:         Patryk Zadarnowski
-maintainer:     Patryk Zadarnowski <pat@jantar.org>
+name:               quiver-bytestring
+version:            1.0.0
+synopsis:           Quiver combinators for bytestring streaming
+homepage:           https://github.com/zadarnowski/quiver-bytestring
+category:           Control
+stability:          alpha
 
-copyright:      Copyright (c) 2015 Patryk Zadarnowski
+author:             Patryk Zadarnowski
+maintainer:         Patryk Zadarnowski <pat@jantar.org>
 
-description:
+copyright:          Copyright (c) 2015 Patryk Zadarnowski
 
-    This library provides a set of combinators for efficient
-    streaming of bytestring data in the Quiver framework.
+description:        This library provides a set of combinators for efficient
+                    streaming of bytestring data in the Quiver framework.
 
-cabal-version:  >= 1.18
-build-type:     Simple
-license:        BSD3
-license-file:   LICENSE
+cabal-version:      >= 1.18
+build-type:         Simple
+license:            BSD3
+license-file:       LICENSE
+extra-source-files: README.md
 
 source-repository head
-  type:         git
-  location:     https://github.com/zadarnowski/quiver-bytestring.git
+  type:     git
+  location: https://github.com/zadarnowski/quiver-bytestring.git
 
 source-repository this
-  type:         git
-  location:     https://github.com/zadarnowski/quiver-bytestring.git
-  tag:          0.0.0.2
+  type:     git
+  location: https://github.com/zadarnowski/quiver-bytestring.git
+  tag:      1.0.0
 
 library
   hs-source-dirs:   src
   default-language: Haskell2010
-  ghc-options:      -Wall -fno-warn-unused-do-bind -fno-warn-missing-signatures
-
-  exposed-modules:
-    Control.Quiver.ByteString
-
+  ghc-options:      -O2 -Wall -fno-warn-unused-do-bind -fno-warn-missing-signatures
+  exposed-modules:  Control.Quiver.ByteString
   build-depends:
-    base                    >= 4.8 && < 5,
-    bytestring              >= 0.10.6.0,
-    quiver                  >= 0.0.0.10
+    base            >= 4.8 && < 5,
+    bytestring      >= 0.10.6.0,
+    quiver          >= 1.0.0
diff --git a/src/Control/Quiver/ByteString.lhs b/src/Control/Quiver/ByteString.lhs
--- a/src/Control/Quiver/ByteString.lhs
+++ b/src/Control/Quiver/ByteString.lhs
@@ -19,11 +19,16 @@
 
 > module Control.Quiver.ByteString (
 >   toChunks, fromChunks, fromChunks',
+>   qGet, qPut,
+>   qReadFile, qWriteFile, qAppendFile,
 > ) where
 
+> import Control.Exception
+> import Control.Monad
+> import Control.Quiver.SP
 > import Data.ByteString (ByteString)
 > import Data.Int
-> import Control.Quiver.SP
+> import System.IO
 
 > import qualified Data.ByteString as ByteString
 > import qualified Data.ByteString.Lazy as Lazy
@@ -109,3 +114,44 @@
 >                     GT -> let (c1, c2) = ByteString.splitAt (fromIntegral r) c in Lazy.fromChunks (reverse (c1:cs)) >:> loop2 n [] c2 (cl - r)
 
 > loope cs = deliver (if null cs then SPComplete else SPFailed (reverse cs))
+
+> -- | Quiver producer that reads the specified file handle in strict chunks,
+> --   each up to @n@ bytes in size.
+
+> qGet :: Handle -> Int -> SProducer ByteString IO IOException
+> qGet h n = loop
+>  where
+>   loop = join $ qlift $ catch (ByteString.hGetSome h n >>= return . produceChunk) (return . spfailed)
+>   produceChunk x
+>     | ByteString.null x = spcomplete
+>     | otherwise = x >:> loop
+
+> -- | Quiver consumer that writes its input to the specified file handle.
+
+> qPut :: Handle -> SConsumer ByteString IO IOException
+> qPut h = loop
+>  where
+>   loop = consume () writeChunk spcomplete
+>   writeChunk x = join $ qlift $ catch (ByteString.hPut h x >> return loop) (return . spfailed)
+
+> -- | Quiver producer that reads the specified file in strict chunks,
+> --   each up to @n@ bytes in size.
+
+> qReadFile :: FilePath -> Int -> SProducer ByteString IO IOException
+> qReadFile f n = join $ qlift $ catch (openBinaryFile f ReadMode >>= return . loop) (return . spfailed)
+>  where
+>   loop h = qhoist (flip onException $ hClose h) (qGet h n) >>= \r -> qlift (hClose h) >> return r
+
+> -- | Quiver consumer that writes its input to the specified file.
+
+> qWriteFile :: FilePath -> SConsumer ByteString IO IOException
+> qWriteFile f = join $ qlift $ catch (openBinaryFile f WriteMode >>= return . loop) (return . spfailed)
+>  where
+>   loop h = qhoist (flip onException $ hClose h) (qPut h) >>= \r -> qlift (hClose h) >> return r
+
+> -- | Quiver consumer that appends its input to the specified file.
+
+> qAppendFile :: FilePath -> SConsumer ByteString IO IOException
+> qAppendFile f = join $ qlift $ catch (openBinaryFile f AppendMode >>= return . loop) (return . spfailed)
+>  where
+>   loop h = qhoist (flip onException $ hClose h) (qPut h) >>= \r -> qlift (hClose h) >> return r
