diff --git a/src/main/java/azgracompress/cache/ICacheFile.java b/src/main/java/azgracompress/cache/ICacheFile.java
index 1d754094b010611af549a0647eae3c8a923517fc..5cf5b8dac9ce60d6aee545e4392faf5d6b9c5ca4 100644
--- a/src/main/java/azgracompress/cache/ICacheFile.java
+++ b/src/main/java/azgracompress/cache/ICacheFile.java
@@ -10,6 +10,8 @@ public interface ICacheFile {
 
     void readFromStream(DataInputStream inputStream) throws IOException;
 
+    void readFromStream(DataInputStream inputStream, CacheFileHeader header) throws IOException;
+
     CacheFileHeader getHeader();
 
     void report(StringBuilder builder);
diff --git a/src/main/java/azgracompress/cache/QuantizationCacheManager.java b/src/main/java/azgracompress/cache/QuantizationCacheManager.java
index 73858a75397f32bec411580f015a3df20806b403..77a342731337b5617d02df137db417462ddd4054 100644
--- a/src/main/java/azgracompress/cache/QuantizationCacheManager.java
+++ b/src/main/java/azgracompress/cache/QuantizationCacheManager.java
@@ -36,7 +36,7 @@ public class QuantizationCacheManager {
     private File getCacheFilePathForSQ(final String trainFile, final int codebookSize) {
         final File inputFile = new File(trainFile);
         return new File(cacheFolder, String.format("%s_%d_bits.qvc",
-                inputFile.getName(), codebookSize));
+                                                   inputFile.getName(), codebookSize));
     }
 
     /**
@@ -52,7 +52,7 @@ public class QuantizationCacheManager {
                                        final V3i vDim) {
         final File inputFile = new File(trainFile);
         return new File(cacheFolder, String.format("%s_%d_%dx%dx%d.qvc", inputFile.getName(), codebookSize,
-                vDim.getX(), vDim.getY(), vDim.getZ()));
+                                                   vDim.getX(), vDim.getY(), vDim.getZ()));
     }
 
 
@@ -143,8 +143,8 @@ public class QuantizationCacheManager {
      */
     public String saveCodebook(final String trainFile, final VQCodebook codebook) throws IOException {
         final String fileName = getCacheFilePathForVQ(trainFile,
-                codebook.getCodebookSize(),
-                codebook.getVectorDims()).getAbsolutePath();
+                                                      codebook.getCodebookSize(),
+                                                      codebook.getVectorDims()).getAbsolutePath();
 
         final CacheFileHeader header = createHeaderForVQ(new File(trainFile).getName(), codebook);
         final VQCacheFile cacheFile = new VQCacheFile(header, codebook);
@@ -282,6 +282,21 @@ public class QuantizationCacheManager {
         return null;
     }
 
+    public static ICacheFile readCacheFile(final String path) {
+        try (FileInputStream fis = new FileInputStream(path);
+             DataInputStream dis = new DataInputStream(fis)) {
+            CacheFileHeader header = new CacheFileHeader();
+            header.readFromStream(dis);
+
+            ICacheFile cacheFile = getCacheFile(header.getQuantizationType());
+            assert (cacheFile != null);
+            cacheFile.readFromStream(dis, header);
+            return cacheFile;
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
     /**
      * Inspect cache file specified by the path.
      *
diff --git a/src/main/java/azgracompress/cache/SQCacheFile.java b/src/main/java/azgracompress/cache/SQCacheFile.java
index b92428eb1ba94f0c0f92e39ceb6e5bd53f449de5..f7ffe5a1089ec40f4336301f8137a77acaaa1b9c 100644
--- a/src/main/java/azgracompress/cache/SQCacheFile.java
+++ b/src/main/java/azgracompress/cache/SQCacheFile.java
@@ -5,8 +5,6 @@ import azgracompress.quantization.scalar.SQCodebook;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
-import java.util.Arrays;
-import java.util.stream.Collectors;
 
 public class SQCacheFile implements ICacheFile {
     private CacheFileHeader header;
@@ -36,9 +34,11 @@ public class SQCacheFile implements ICacheFile {
 
     public void readFromStream(DataInputStream inputStream) throws IOException {
         header = new CacheFileHeader();
-
         header.readFromStream(inputStream);
+        readFromStream(inputStream, header);
+    }
 
+    public void readFromStream(DataInputStream inputStream, CacheFileHeader header) throws IOException {
         final int codebookSize = header.getCodebookSize();
         final int[] centroids = new int[codebookSize];
         final long[] frequencies = new long[codebookSize];
diff --git a/src/main/java/azgracompress/cache/VQCacheFile.java b/src/main/java/azgracompress/cache/VQCacheFile.java
index 6e6f54de776a3f49fb5dddd043e7934ff1a080cd..3710810e63c48955d4aedd86464df9a256869ec8 100644
--- a/src/main/java/azgracompress/cache/VQCacheFile.java
+++ b/src/main/java/azgracompress/cache/VQCacheFile.java
@@ -38,9 +38,12 @@ public class VQCacheFile implements ICacheFile {
 
     public void readFromStream(DataInputStream inputStream) throws IOException {
         header = new CacheFileHeader();
-
         header.readFromStream(inputStream);
+        readFromStream(inputStream, header);
+    }
 
+    @Override
+    public void readFromStream(DataInputStream inputStream, CacheFileHeader header) throws IOException {
         final int codebookSize = header.getCodebookSize();
         final CodebookEntry[] vectors = new CodebookEntry[codebookSize];
         final long[] frequencies = new long[codebookSize];
diff --git a/src/main/java/azgracompress/quantization/vector/VQCodebook.java b/src/main/java/azgracompress/quantization/vector/VQCodebook.java
index c2a53f64643a45d33cb568980c6a9f5deaf41037..1afb8d2274d81aa703df336b0ce86c18e86e2dcf 100644
--- a/src/main/java/azgracompress/quantization/vector/VQCodebook.java
+++ b/src/main/java/azgracompress/quantization/vector/VQCodebook.java
@@ -43,6 +43,16 @@ public class VQCodebook {
         return vectors;
     }
 
+    public int[][] getRawVectors() {
+        assert (codebookSize == vectors.length);
+        assert (vectors[0].getVector().length == (int) vectorDims.multiplyTogether());
+        final int[][] rawCodebook = new int[vectors.length][(int) vectorDims.multiplyTogether()];
+        for (int i = 0; i < codebookSize; i++) {
+            rawCodebook[i] = vectors[i].getVector();
+        }
+        return rawCodebook;
+    }
+
     /**
      * Get frequencies of codebook vectors at indices.
      *