diff --git a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
index 269b3a2997e12e464632eb090958be68a409966b..55df263fe5200e7b6ef24d88cf02495054fe123a 100644
--- a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
+++ b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
@@ -19,10 +19,11 @@ package com.android.inputmethod.latin;
 import android.content.Context;
 import android.util.Log;
 
+import com.android.inputmethod.latin.makedict.DictEncoder;
 import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
+import com.android.inputmethod.latin.makedict.Ver3DictEncoder;
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 
 // TODO: Quit extending Dictionary after implementing dynamic binary dictionary.
@@ -49,32 +50,21 @@ abstract public class AbstractDictionaryWriter extends Dictionary {
 
     abstract public void removeBigramWords(final String word0, final String word1);
 
-    abstract protected void writeBinaryDictionary(final FileOutputStream out)
+    abstract protected void writeDictionary(final DictEncoder dictEncoder)
             throws IOException, UnsupportedFormatException;
 
     public void write(final String fileName) {
         final String tempFileName = fileName + ".temp";
         final File file = new File(mContext.getFilesDir(), fileName);
         final File tempFile = new File(mContext.getFilesDir(), tempFileName);
-        FileOutputStream out = null;
         try {
-            out = new FileOutputStream(tempFile);
-            writeBinaryDictionary(out);
-            out.flush();
-            out.close();
+            final DictEncoder dictEncoder = new Ver3DictEncoder(file);
+            writeDictionary(dictEncoder);
             tempFile.renameTo(file);
         } catch (IOException e) {
             Log.e(TAG, "IO exception while writing file", e);
         } catch (UnsupportedFormatException e) {
             Log.e(TAG, "Unsupported format", e);
-        } finally {
-            if (out != null) {
-                try {
-                    out.close();
-                } catch (IOException e) {
-                    // ignore
-                }
-            }
         }
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/DictionaryWriter.java b/java/src/com/android/inputmethod/latin/DictionaryWriter.java
index b3a572809f9e12def0f1c4ef6c0f786107b3e6e7..a97e053d0ad974a6450d237937a59d107047c4fc 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryWriter.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryWriter.java
@@ -20,7 +20,7 @@ import android.content.Context;
 
 import com.android.inputmethod.keyboard.ProximityInfo;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.makedict.BinaryDictEncoderUtils;
+import com.android.inputmethod.latin.makedict.DictEncoder;
 import com.android.inputmethod.latin.makedict.FormatSpec;
 import com.android.inputmethod.latin.makedict.FusionDictionary;
 import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
@@ -28,7 +28,6 @@ import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
 import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
 import com.android.inputmethod.latin.utils.CollectionUtils;
 
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -85,9 +84,9 @@ public class DictionaryWriter extends AbstractDictionaryWriter {
     }
 
     @Override
-    protected void writeBinaryDictionary(final FileOutputStream out)
+    protected void writeDictionary(final DictEncoder dictEncoder)
             throws IOException, UnsupportedFormatException {
-        BinaryDictEncoderUtils.writeDictionaryBinary(out, mFusionDictionary, FORMAT_OPTIONS);
+        dictEncoder.writeDictionary(mFusionDictionary, FORMAT_OPTIONS);
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..89c982e7b7a00c11db72397c9bc4c057e69f23f0
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.makedict;
+
+import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
+
+import java.io.IOException;
+
+/**
+ * An interface of binary dictionary encoder.
+ */
+public interface DictEncoder {
+    public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions)
+            throws IOException, UnsupportedFormatException;
+}
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..e81fd4514f16b3e22ae7e88bb2bb772534bcf57b
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.makedict;
+
+import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An implementation of DictEncoder for version 3 binary dictionary.
+ */
+public class Ver3DictEncoder implements DictEncoder {
+
+    private final File mDictFile;
+    private OutputStream mOutStream;
+
+    public Ver3DictEncoder(final File dictFile) {
+        mDictFile = dictFile;
+        mOutStream = null;
+    }
+
+    // This constructor is used only by BinaryDictOffdeviceUtilsTests.
+    // If you want to use this in the production code, you should consider keeping consistency of
+    // the interface of Ver3DictDecoder by using factory.
+    public Ver3DictEncoder(final OutputStream outStream) {
+        mDictFile = null;
+        mOutStream = outStream;
+    }
+
+    private void openStream() throws FileNotFoundException {
+        mOutStream = new FileOutputStream(mDictFile);
+    }
+
+    private void close() throws IOException {
+        if (mOutStream != null) {
+            mOutStream.close();
+            mOutStream = null;
+        }
+    }
+
+    @Override
+    public void writeDictionary(FusionDictionary dict, FormatOptions formatOptions)
+            throws IOException, UnsupportedFormatException {
+        if (mOutStream == null) {
+            openStream();
+        }
+        BinaryDictEncoderUtils.writeDictionaryBinary(mOutStream, dict, formatOptions);
+        close();
+    }
+}
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
index f30be97f3164fa28a6fabea77d4131f9c1e7762d..83ccdec599334c06a0eb29de85b871b39906368b 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
@@ -32,7 +32,6 @@ import com.android.inputmethod.latin.utils.CollectionUtils;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -204,17 +203,14 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
         long now = -1, diff = -1;
 
         try {
-            final FileOutputStream out = new FileOutputStream(file);
+            final DictEncoder dictEncoder = new Ver3DictEncoder(file);
 
             now = System.currentTimeMillis();
             // If you need to dump the dict to a textual file, uncomment the line below and the
             // function above
             // dumpToCombinedFileForDebug(file, "/tmp/foo");
-            BinaryDictEncoderUtils.writeDictionaryBinary(out, dict, formatOptions);
+            dictEncoder.writeDictionary(dict, formatOptions);
             diff = System.currentTimeMillis() - now;
-
-            out.flush();
-            out.close();
         } catch (IOException e) {
             Log.e(TAG, "IO exception while writing file", e);
         } catch (UnsupportedFormatException e) {
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
index 68976a7ca591046c027863b556288af8eb701e68..b13b5a15f8cc9863e09149ec3ede7f16a1754cfb 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
@@ -252,9 +252,8 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
         dict.add("abcd", 10, null, false);
 
         try {
-            final FileOutputStream out = new FileOutputStream(file);
-            BinaryDictEncoderUtils.writeDictionaryBinary(out, dict, FORMAT_OPTIONS);
-            out.close();
+            final DictEncoder dictEncoder = new Ver3DictEncoder(file);
+            dictEncoder.writeDictionary(dict, FORMAT_OPTIONS);
         } catch (IOException e) {
             fail("IOException while writing an initial dictionary : " + e);
         } catch (UnsupportedFormatException e) {
@@ -304,9 +303,8 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
         dict.add("efgh", 15, null, false);
 
         try {
-            final FileOutputStream out = new FileOutputStream(file);
-            BinaryDictEncoderUtils.writeDictionaryBinary(out, dict, FORMAT_OPTIONS);
-            out.close();
+            final DictEncoder dictEncoder = new Ver3DictEncoder(file); 
+            dictEncoder.writeDictionary(dict, FORMAT_OPTIONS);
         } catch (IOException e) {
             fail("IOException while writing an initial dictionary : " + e);
         } catch (UnsupportedFormatException e) {
@@ -342,9 +340,8 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
         dict.add("initial", 10, null, false);
 
         try {
-            final FileOutputStream out = new FileOutputStream(file);
-            BinaryDictEncoderUtils.writeDictionaryBinary(out, dict, FORMAT_OPTIONS);
-            out.close();
+            final DictEncoder dictEncoder = new Ver3DictEncoder(file);
+            dictEncoder.writeDictionary(dict, FORMAT_OPTIONS);
         } catch (IOException e) {
             assertTrue(false);
         } catch (UnsupportedFormatException e) {
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
index fee445389fb230541110725139b2d3dd067d3bf9..6c1a9de582ab5cd2d36aa966f27e1610d18465d3 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
@@ -17,18 +17,18 @@
 package com.android.inputmethod.latin.dicttool;
 
 import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils;
-import com.android.inputmethod.latin.makedict.BinaryDictEncoderUtils;
+import com.android.inputmethod.latin.makedict.DictEncoder;
 import com.android.inputmethod.latin.makedict.FormatSpec;
 import com.android.inputmethod.latin.makedict.FusionDictionary;
 import com.android.inputmethod.latin.makedict.MakedictLog;
 import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
 import com.android.inputmethod.latin.makedict.Ver3DictDecoder;
+import com.android.inputmethod.latin.makedict.Ver3DictEncoder;
 
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.util.Arrays;
@@ -358,8 +358,8 @@ public class DictionaryMaker {
             throws FileNotFoundException, IOException, UnsupportedFormatException {
         final File outputFile = new File(outputFilename);
         final FormatSpec.FormatOptions formatOptions = new FormatSpec.FormatOptions(version);
-        BinaryDictEncoderUtils.writeDictionaryBinary(new FileOutputStream(outputFilename), dict,
-                formatOptions);
+        final DictEncoder dictEncoder = new Ver3DictEncoder(outputFile);
+        dictEncoder.writeDictionary(dict, formatOptions);
     }
 
     /**
diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
index da51387be9f6897f2bbba70524765d695ef57288..2b2661a0c01cefb5706bc7b77ae85389a0a0baef 100644
--- a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
+++ b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
@@ -17,13 +17,14 @@
 package com.android.inputmethod.latin.dicttool;
 
 import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils;
-import com.android.inputmethod.latin.makedict.BinaryDictEncoderUtils;
+import com.android.inputmethod.latin.makedict.DictEncoder;
 import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
 import com.android.inputmethod.latin.makedict.FusionDictionary;
 import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
 import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
 import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
 import com.android.inputmethod.latin.makedict.Ver3DictDecoder;
+import com.android.inputmethod.latin.makedict.Ver3DictEncoder;
 
 import junit.framework.TestCase;
 
@@ -53,12 +54,13 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase {
 
         final File dst = File.createTempFile("testGetRawDict", ".tmp");
         dst.deleteOnExit();
+
         final OutputStream out = Compress.getCompressedStream(
                 Compress.getCompressedStream(
                         Compress.getCompressedStream(
                                 new BufferedOutputStream(new FileOutputStream(dst)))));
-
-        BinaryDictEncoderUtils.writeDictionaryBinary(out, dict, new FormatOptions(2, false));
+        final DictEncoder dictEncoder = new Ver3DictEncoder(out);
+        dictEncoder.writeDictionary(dict, new FormatOptions(2, false));
 
         // Test for an actually compressed dictionary and its contents
         final BinaryDictOffdeviceUtils.DecoderChainSpec decodeSpec =