diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # libarchive
 
+## 0.2.1.2
+
+  * Stream from a file when using `unpackArchive`
+
 ## 0.2.1.1
 
   * Preserve modification times by default
diff --git a/cbits/unpack.c b/cbits/unpack.c
--- a/cbits/unpack.c
+++ b/cbits/unpack.c
@@ -3,19 +3,7 @@
 #include <archive.h>
 #include <archive_entry.h>
 
-// Unpack a tar archive (stored in a bytestring) into a particular directory
-void unpack_in_dir(char* dirname, void *buff, size_t size) {
-
-    // step 1: allocate/initialize archive struct
-    struct archive *a;
-    struct archive_entry *entry;
-    a = archive_read_new();
-
-    // autodetect archive format/compression
-    archive_read_support_format_all(a);
-
-    // open from memory (bytestring)
-    archive_read_open_memory(a, buff, size);
+void unpack_common(char* dirname, struct archive *a, struct archive_entry *entry) {
 
     while (archive_read_next_header(a, &entry) == ARCHIVE_OK || archive_read_next_header(a, &entry) == ARCHIVE_RETRY) {
         const char* pre_path_name = archive_entry_pathname(entry);
@@ -32,4 +20,41 @@
     free(dirname);
 
     archive_read_free(a);
+
+}
+
+void unpack_from_file(char* dirname, char* filepath) {
+
+    // allocate/initialize archive struct
+    struct archive *a;
+    struct archive_entry *entry;
+    a = archive_read_new();
+
+    // autodetect archive format/compression
+    archive_read_support_format_all(a);
+
+    // open from file
+    archive_read_open_filename(a, filepath, 10240);
+
+    unpack_common(dirname, a, entry);
+
+}
+
+
+// Unpack a tar archive (stored in a bytestring) into a particular directory
+void unpack_in_dir(char* dirname, void *buff, size_t size) {
+
+    // step 1: allocate/initialize archive struct
+    struct archive *a;
+    struct archive_entry *entry;
+    a = archive_read_new();
+
+    // autodetect archive format/compression
+    archive_read_support_format_all(a);
+
+    // open from memory (bytestring)
+    archive_read_open_memory(a, buff, size);
+
+    unpack_common(dirname, a, entry);
+
 }
diff --git a/libarchive.cabal b/libarchive.cabal
--- a/libarchive.cabal
+++ b/libarchive.cabal
@@ -1,6 +1,6 @@
 cabal-version: 1.18
 name: libarchive
-version: 0.2.1.1
+version: 0.2.1.2
 license: BSD3
 license-file: LICENSE
 copyright: Copyright: (c) 2018-2019 Vanessa McHale
diff --git a/src/Codec/Archive.hs b/src/Codec/Archive.hs
--- a/src/Codec/Archive.hs
+++ b/src/Codec/Archive.hs
@@ -3,12 +3,25 @@
     , unpackArchive
     ) where
 
-import           Codec.Archive.Foreign (unpackToDir)
+import           Codec.Archive.Foreign
+import           Data.ByteString       (useAsCStringLen)
 import qualified Data.ByteString       as BS
+import           Foreign.C.String
+import           System.FilePath       (pathSeparator)
 
 unpackArchive :: FilePath -- ^ Filepath pointing to archive
               -> FilePath -- ^ Filepath to unpack to
               -> IO ()
 unpackArchive tarFp dirFp = do
-    contents <- BS.readFile tarFp
-    unpackToDir dirFp contents
+    fp' <- newCString tarFp
+    dir' <- newCString (dirFp ++ [pathSeparator])
+    unpack_from_file dir' fp'
+
+unpackToDir :: FilePath -- ^ Directory to unpack in
+            -> BS.ByteString -- ^ 'ByteString' containing archive
+            -> IO ()
+unpackToDir fp bs = do
+    fp' <- newCString (fp ++ [pathSeparator])
+    useAsCStringLen bs $
+        \(charPtr, sz) ->
+            unpack_in_dir fp' charPtr (fromIntegral sz)
diff --git a/src/Codec/Archive/Foreign.hs b/src/Codec/Archive/Foreign.hs
--- a/src/Codec/Archive/Foreign.hs
+++ b/src/Codec/Archive/Foreign.hs
@@ -1,20 +1,11 @@
-module Codec.Archive.Foreign ( unpackToDir
+module Codec.Archive.Foreign ( unpack_in_dir
+                             , unpack_from_file
                              ) where
 
-import           Data.ByteString  as BS
 import           Data.Word        (Word)
 import           Foreign.C.String
 import           Foreign.C.Types
 import           Foreign.Ptr
-import           System.FilePath  (pathSeparator)
 
 foreign import ccall unsafe unpack_in_dir :: CString -> Ptr CChar -> Word -> IO ()
-
-unpackToDir :: FilePath -- ^ Directory to unpack in
-            -> BS.ByteString -- ^ 'ByteString' containing archive
-            -> IO ()
-unpackToDir fp bs = do
-    fp' <- newCString (fp ++ [pathSeparator])
-    useAsCStringLen bs $
-        \(charPtr, sz) ->
-            unpack_in_dir fp' charPtr (fromIntegral sz)
+foreign import ccall unsafe unpack_from_file :: CString -> CString -> IO ()
