diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
index 2cbc04154e63ae2ed1c0c094bd8ff114e78da402..3ef03f4bd43437a8dd38584eb7cd9a75768b7c55 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
@@ -26,11 +26,13 @@ import org.xml.sax.SAXException;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.util.ArrayList;
 
@@ -51,14 +53,17 @@ public final class BinaryDictOffdeviceUtils {
     public final static String ENCRYPTION = "encrypted";
 
     private final static int MAX_DECODE_DEPTH = 8;
+    private final static int COPY_BUFFER_SIZE = 8192;
 
     public static class DecoderChainSpec {
         ArrayList<String> mDecoderSpec = new ArrayList<>();
         File mFile;
+
         public DecoderChainSpec addStep(final String stepDescription) {
             mDecoderSpec.add(stepDescription);
             return this;
         }
+
         public String describeChain() {
             final StringBuilder s = new StringBuilder("raw");
             for (final String step : mDecoderSpec) {
@@ -70,13 +75,10 @@ public final class BinaryDictOffdeviceUtils {
     }
 
     public static void copy(final InputStream input, final OutputStream output) throws IOException {
-        final byte[] buffer = new byte[1000];
-        final BufferedInputStream in = new BufferedInputStream(input);
-        final BufferedOutputStream out = new BufferedOutputStream(output);
-        for (int readBytes = in.read(buffer); readBytes >= 0; readBytes = in.read(buffer))
+        final byte[] buffer = new byte[COPY_BUFFER_SIZE];
+        for (int readBytes = input.read(buffer); readBytes >= 0; readBytes = input.read(buffer)) {
             output.write(buffer, 0, readBytes);
-        in.close();
-        out.close();
+        }
     }
 
     /**
@@ -131,11 +133,15 @@ public final class BinaryDictOffdeviceUtils {
         try {
             final File dst = File.createTempFile(PREFIX, SUFFIX);
             dst.deleteOnExit();
-            final FileOutputStream dstStream = new FileOutputStream(dst);
-            copy(Compress.getUncompressedStream(new BufferedInputStream(new FileInputStream(src))),
-                    new BufferedOutputStream(dstStream)); // #copy() closes the streams
-            return dst;
-        } catch (IOException e) {
+            try (
+                final InputStream input = Compress.getUncompressedStream(
+                        new BufferedInputStream(new FileInputStream(src)));
+                final OutputStream output = new BufferedOutputStream(new FileOutputStream(dst))
+            ) {
+                copy(input, output);
+                return dst;
+            }
+        } catch (final IOException e) {
             // Could not uncompress the file: presumably the file is simply not a compressed file
             return null;
         }
@@ -150,20 +156,20 @@ public final class BinaryDictOffdeviceUtils {
         try {
             final File dst = File.createTempFile(PREFIX, SUFFIX);
             dst.deleteOnExit();
-            final FileOutputStream dstStream = new FileOutputStream(dst);
-            copy(Crypt.getDecryptedStream(new BufferedInputStream(new FileInputStream(src))),
-                    dstStream); // #copy() closes the streams
-            return dst;
-        } catch (IOException e) {
+            try (
+                final InputStream input = Crypt.getDecryptedStream(
+                        new BufferedInputStream(new FileInputStream(src)));
+                final OutputStream output = new BufferedOutputStream(new FileOutputStream(dst))
+            ) {
+                copy(input, output);
+                return dst;
+            }
+        } catch (final IOException e) {
             // Could not decrypt the file: presumably the file is simply not a crypted file
             return null;
         }
     }
 
-    static void crash(final String filename, final Exception e) {
-        throw new RuntimeException("Can't read file " + filename, e);
-    }
-
     static FusionDictionary getDictionary(final String filename, final boolean report) {
         final File file = new File(filename);
         if (report) {
@@ -172,45 +178,40 @@ public final class BinaryDictOffdeviceUtils {
         }
         try {
             if (XmlDictInputOutput.isXmlUnigramDictionary(filename)) {
-                if (report) System.out.println("Format : XML unigram list");
+                if (report) {
+                    System.out.println("Format : XML unigram list");
+                }
                 return XmlDictInputOutput.readDictionaryXml(
                         new BufferedInputStream(new FileInputStream(file)),
                         null /* shortcuts */, null /* bigrams */);
-            } else {
-                final DecoderChainSpec decodedSpec = getRawDictionaryOrNull(file);
-                if (null == decodedSpec) {
-                    crash(filename, new RuntimeException(
-                            filename + " does not seem to be a dictionary file"));
-                } else if (CombinedInputOutput.isCombinedDictionary(
-                        decodedSpec.mFile.getAbsolutePath())){
-                    if (report) {
-                        System.out.println("Format : Combined format");
-                        System.out.println("Packaging : " + decodedSpec.describeChain());
-                        System.out.println("Uncompressed size : " + decodedSpec.mFile.length());
-                    }
-                    return CombinedInputOutput.readDictionaryCombined(
-                            new BufferedInputStream(new FileInputStream(decodedSpec.mFile)));
-                } else {
-                    final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(
-                            decodedSpec.mFile, 0, decodedSpec.mFile.length(),
-                            DictDecoder.USE_BYTEARRAY);
-                    if (report) {
-                        System.out.println("Format : Binary dictionary format");
-                        System.out.println("Packaging : " + decodedSpec.describeChain());
-                        System.out.println("Uncompressed size : " + decodedSpec.mFile.length());
-                    }
-                    return dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */);
+            }
+            final DecoderChainSpec decodedSpec = getRawDictionaryOrNull(file);
+            if (null == decodedSpec) {
+                throw new RuntimeException("Does not seem to be a dictionary file " + filename);
+            }
+            if (CombinedInputOutput.isCombinedDictionary(decodedSpec.mFile.getAbsolutePath())) {
+                if (report) {
+                    System.out.println("Format : Combined format");
+                    System.out.println("Packaging : " + decodedSpec.describeChain());
+                    System.out.println("Uncompressed size : " + decodedSpec.mFile.length());
                 }
+                try (final BufferedReader reader = new BufferedReader(
+                        new InputStreamReader(new FileInputStream(decodedSpec.mFile), "UTF-8"))) {
+                    return CombinedInputOutput.readDictionaryCombined(reader);
+                }
+            }
+            final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(
+                    decodedSpec.mFile, 0, decodedSpec.mFile.length(),
+                    DictDecoder.USE_BYTEARRAY);
+            if (report) {
+                System.out.println("Format : Binary dictionary format");
+                System.out.println("Packaging : " + decodedSpec.describeChain());
+                System.out.println("Uncompressed size : " + decodedSpec.mFile.length());
             }
-        } catch (IOException e) {
-            crash(filename, e);
-        } catch (SAXException e) {
-            crash(filename, e);
-        } catch (ParserConfigurationException e) {
-            crash(filename, e);
-        } catch (UnsupportedFormatException e) {
-            crash(filename, e);
+            return dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */);
+        } catch (final IOException | SAXException | ParserConfigurationException |
+                UnsupportedFormatException e) {
+            throw new RuntimeException("Can't read file " + filename, e);
         }
-        return null;
     }
 }
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java
index 6a0e1b7f0f9e145d1eb5804145bbe00b704a978f..23cbee81c461925153cd95958a00844eedfab6f0 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java
@@ -26,13 +26,9 @@ import com.android.inputmethod.latin.makedict.WordProperty;
 import com.android.inputmethod.latin.utils.CombinedFormatUtils;
 
 import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
+import java.io.BufferedWriter;
 import java.io.FileReader;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Writer;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.TreeSet;
@@ -57,27 +53,15 @@ public class CombinedInputOutput {
      * @return true if the file is in the combined format, false otherwise
      */
     public static boolean isCombinedDictionary(final String filename) {
-        BufferedReader reader = null;
-        try {
-            reader = new BufferedReader(new FileReader(new File(filename)));
+        try (final BufferedReader reader = new BufferedReader(new FileReader(filename))) {
             String firstLine = reader.readLine();
             while (firstLine.startsWith(COMMENT_LINE_STARTER)) {
                 firstLine = reader.readLine();
             }
             return firstLine.matches(
                     "^" + CombinedFormatUtils.DICTIONARY_TAG + "=[^:]+(:[^=]+=[^:]+)*");
-        } catch (FileNotFoundException e) {
+        } catch (final IOException e) {
             return false;
-        } catch (IOException e) {
-            return false;
-        } finally {
-            if (reader != null) {
-                try {
-                    reader.close();
-                } catch (IOException e) {
-                    // do nothing
-                }
-            }
         }
     }
 
@@ -87,12 +71,11 @@ public class CombinedInputOutput {
      * This is the public method that will read a combined file and return the corresponding memory
      * representation.
      *
-     * @param source the file to read the data from.
+     * @param reader the buffered reader to read the data from.
      * @return the in-memory representation of the dictionary.
      */
-    public static FusionDictionary readDictionaryCombined(final InputStream source)
+    public static FusionDictionary readDictionaryCombined(final BufferedReader reader)
             throws IOException {
-        final BufferedReader reader = new BufferedReader(new InputStreamReader(source, "UTF-8"));
         String headerLine = reader.readLine();
         while (headerLine.startsWith(COMMENT_LINE_STARTER)) {
             headerLine = reader.readLine();
@@ -218,11 +201,11 @@ public class CombinedInputOutput {
     /**
      * Writes a dictionary to a combined file.
      *
-     * @param destination a destination stream to write to.
+     * @param destination a destination writer.
      * @param dict the dictionary to write.
      */
-    public static void writeDictionaryCombined(
-            final Writer destination, final FusionDictionary dict) throws IOException {
+    public static void writeDictionaryCombined(final BufferedWriter destination,
+            final FusionDictionary dict) throws IOException {
         final TreeSet<WordProperty> wordPropertiesInDict = new TreeSet<>();
         for (final WordProperty wordProperty : dict) {
             // This for ordering by frequency, then by asciibetic order
@@ -232,6 +215,5 @@ public class CombinedInputOutput {
         for (final WordProperty wordProperty : wordPropertiesInDict) {
             destination.write(CombinedFormatUtils.formatWordProperty(wordProperty));
         }
-        destination.close();
     }
 }
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Compress.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Compress.java
index b7f48b522b1bd5daeb5667f20693591954cfaf15..728a159a0d8548592d72113a8a684fd09c3a61d8 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Compress.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Compress.java
@@ -16,11 +16,6 @@
 
 package com.android.inputmethod.latin.dicttool;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -32,8 +27,7 @@ public class Compress {
         // This container class is not publicly instantiable.
     }
 
-    public static OutputStream getCompressedStream(final OutputStream out)
-        throws java.io.IOException {
+    public static OutputStream getCompressedStream(final OutputStream out) throws IOException {
         return new GZIPOutputStream(out);
     }
 
@@ -43,7 +37,6 @@ public class Compress {
 
     static public class Compressor extends Dicttool.Command {
         public static final String COMMAND = "compress";
-        public static final String STDIN_OR_STDOUT = "-";
 
         public Compressor() {
         }
@@ -61,17 +54,18 @@ public class Compress {
             }
             final String inFilename = mArgs.length >= 1 ? mArgs[0] : STDIN_OR_STDOUT;
             final String outFilename = mArgs.length >= 2 ? mArgs[1] : STDIN_OR_STDOUT;
-            final InputStream input = inFilename.equals(STDIN_OR_STDOUT) ? System.in
-                    : new BufferedInputStream(new FileInputStream(new File(inFilename)));
-            final OutputStream output = outFilename.equals(STDIN_OR_STDOUT) ? System.out
-                    : new BufferedOutputStream(new FileOutputStream(new File(outFilename)));
-            BinaryDictOffdeviceUtils.copy(input, new GZIPOutputStream(output));
+            try (
+                final InputStream input = getFileInputStreamOrStdIn(inFilename);
+                final OutputStream compressedOutput = getCompressedStream(
+                        getFileOutputStreamOrStdOut(outFilename))
+            ) {
+                BinaryDictOffdeviceUtils.copy(input, compressedOutput);
+            }
         }
     }
 
     static public class Uncompressor extends Dicttool.Command {
         public static final String COMMAND = "uncompress";
-        public static final String STDIN_OR_STDOUT = "-";
 
         public Uncompressor() {
         }
@@ -89,11 +83,13 @@ public class Compress {
             }
             final String inFilename = mArgs.length >= 1 ? mArgs[0] : STDIN_OR_STDOUT;
             final String outFilename = mArgs.length >= 2 ? mArgs[1] : STDIN_OR_STDOUT;
-            final InputStream input = inFilename.equals(STDIN_OR_STDOUT) ? System.in
-                    : new BufferedInputStream(new FileInputStream(new File(inFilename)));
-            final OutputStream output = outFilename.equals(STDIN_OR_STDOUT) ? System.out
-                    : new BufferedOutputStream(new FileOutputStream(new File(outFilename)));
-            BinaryDictOffdeviceUtils.copy(new GZIPInputStream(input), output);
+            try (
+                final InputStream uncompressedInput = getUncompressedStream(
+                        getFileInputStreamOrStdIn(inFilename));
+                final OutputStream output = getFileOutputStreamOrStdOut(outFilename)
+            ) {
+                BinaryDictOffdeviceUtils.copy(uncompressedInput, output);
+            }
         }
     }
 }
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 37c8d4184f120d0b730439c810455d5a6eba4001..3d0557b5c017e5b18de56900e822a654dd2f478c 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
@@ -27,19 +27,23 @@ import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
 import com.android.inputmethod.latin.makedict.Ver2DictEncoder;
 import com.android.inputmethod.latin.makedict.Ver4DictEncoder;
 
+import org.xml.sax.SAXException;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.util.Arrays;
 import java.util.LinkedList;
 
 import javax.xml.parsers.ParserConfigurationException;
 
-import org.xml.sax.SAXException;
-
 /**
  * Main class/method for DictionaryMaker.
  */
@@ -279,22 +283,21 @@ public class DictionaryMaker {
      */
     private static FusionDictionary readCombinedFile(final String combinedFilename)
         throws FileNotFoundException, IOException {
-        FileInputStream inStream = null;
-        try {
-            final File file = new File(combinedFilename);
-            inStream = new FileInputStream(file);
-            return CombinedInputOutput.readDictionaryCombined(inStream);
-        } finally {
-            if (null != inStream) {
-                try {
-                    inStream.close();
-                } catch (IOException e) {
-                    // do nothing
-                }
-            }
+        try (final BufferedReader reader = new BufferedReader(new InputStreamReader(
+                new FileInputStream(combinedFilename), "UTF-8"))
+        ) {
+            return CombinedInputOutput.readDictionaryCombined(reader);
         }
     }
 
+    private static BufferedInputStream getBufferedFileInputStream(final String filename)
+            throws FileNotFoundException {
+        if (filename == null) {
+            return null;
+        }
+        return new BufferedInputStream(new FileInputStream(filename));
+    }
+
     /**
      * Read a dictionary from a unigram XML file, and optionally a bigram XML file.
      *
@@ -310,12 +313,13 @@ public class DictionaryMaker {
     private static FusionDictionary readXmlFile(final String unigramXmlFilename,
             final String shortcutXmlFilename, final String bigramXmlFilename)
             throws FileNotFoundException, SAXException, IOException, ParserConfigurationException {
-        final FileInputStream unigrams = new FileInputStream(new File(unigramXmlFilename));
-        final FileInputStream shortcuts = null == shortcutXmlFilename ? null :
-                new FileInputStream(new File(shortcutXmlFilename));
-        final FileInputStream bigrams = null == bigramXmlFilename ? null :
-                new FileInputStream(new File(bigramXmlFilename));
-        return XmlDictInputOutput.readDictionaryXml(unigrams, shortcuts, bigrams);
+        try (
+            final BufferedInputStream unigrams = getBufferedFileInputStream(unigramXmlFilename);
+            final BufferedInputStream shortcuts = getBufferedFileInputStream(shortcutXmlFilename);
+            final BufferedInputStream bigrams = getBufferedFileInputStream(bigramXmlFilename);
+        ) {
+            return XmlDictInputOutput.readDictionaryXml(unigrams, shortcuts, bigrams);
+        }
     }
 
     /**
@@ -374,8 +378,9 @@ public class DictionaryMaker {
      */
     private static void writeXmlDictionary(final String outputFilename,
             final FusionDictionary dict) throws FileNotFoundException, IOException {
-        XmlDictInputOutput.writeDictionaryXml(new BufferedWriter(new FileWriter(outputFilename)),
-                dict);
+        try (final BufferedWriter writer = new BufferedWriter(new FileWriter(outputFilename))) {
+            XmlDictInputOutput.writeDictionaryXml(writer, dict);
+        }
     }
 
     /**
@@ -388,7 +393,8 @@ public class DictionaryMaker {
      */
     private static void writeCombinedDictionary(final String outputFilename,
             final FusionDictionary dict) throws FileNotFoundException, IOException {
-        CombinedInputOutput.writeDictionaryCombined(
-                new BufferedWriter(new FileWriter(outputFilename)), dict);
+        try (final BufferedWriter writer = new BufferedWriter(new FileWriter(outputFilename))) {
+            CombinedInputOutput.writeDictionaryCombined(writer, dict);
+        }
     }
 }
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java
index 8ae035f64b99122f1a1bdc5a18136ded811355c2..e49b3508400b0f3f0b6c75b86c113837ed8e1459 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java
@@ -16,23 +16,63 @@
 
 package com.android.inputmethod.latin.dicttool;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.Arrays;
 import java.util.HashMap;
 
 public class Dicttool {
 
     public static abstract class Command {
+        public static final String STDIN_OR_STDOUT = "-";
         protected String[] mArgs;
+
         public void setArgs(String[] args) throws IllegalArgumentException {
             mArgs = args;
         }
+
+        protected static InputStream getFileInputStreamOrStdIn(final String inFilename)
+                throws FileNotFoundException {
+            if (STDIN_OR_STDOUT.equals(inFilename)) {
+                return System.in;
+            }
+            return getFileInputStream(new File(inFilename));
+        }
+
+        protected static InputStream getFileInputStream(final File inFile)
+                throws FileNotFoundException {
+            return new BufferedInputStream(new FileInputStream(inFile));
+        }
+
+        protected static OutputStream getFileOutputStreamOrStdOut(final String outFilename)
+                throws FileNotFoundException {
+            if (STDIN_OR_STDOUT.equals(outFilename)) {
+                return System.out;
+            }
+            return getFileOutputStream(new File(outFilename));
+        }
+
+        protected static OutputStream getFileOutputStream(final File outFile)
+                throws FileNotFoundException {
+            return new BufferedOutputStream(new FileOutputStream(outFile));
+        }
+
         abstract public String getHelp();
         abstract public void run() throws Exception;
     }
+
     static HashMap<String, Class<? extends Command>> sCommands = new HashMap<>();
+
     static {
         CommandList.populate();
     }
+
     public static void addCommand(final String commandName, final Class<? extends Command> cls) {
         sCommands.put(commandName, cls);
     }
@@ -60,7 +100,7 @@ public class Dicttool {
         return sCommands.containsKey(commandName);
     }
 
-    private Command getCommand(final String[] arguments) {
+    private static Command getCommand(final String[] arguments) {
         final String commandName = arguments[0];
         if (!isCommand(commandName)) {
             throw new RuntimeException("Unknown command : " + commandName);
@@ -76,7 +116,7 @@ public class Dicttool {
      * @param arguments the arguments passed to dicttool.
      * @return 0 for success, an error code otherwise (always 1 at the moment)
      */
-    private int execute(final String[] arguments) {
+    private static int execute(final String[] arguments) {
         final Command command = getCommand(arguments);
         try {
             command.run();
@@ -95,6 +135,6 @@ public class Dicttool {
             return;
         }
         // Exit with the success/error code from #execute() as status.
-        System.exit(new Dicttool().execute(arguments));
+        System.exit(execute(arguments));
     }
 }
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java
index dff3387be4741a9582e7c140230d65454f9d7835..1f679826949def020782889bfeb8bb12e5e73f50 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java
@@ -21,8 +21,9 @@ import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 
 public class Package {
     private Package() {
@@ -86,9 +87,13 @@ public class Package {
             }
             System.out.println("Packaging : " + decodedSpec.describeChain());
             System.out.println("Uncompressed size : " + decodedSpec.mFile.length());
-            final FileOutputStream dstStream = new FileOutputStream(new File(mArgs[1]));
-            BinaryDictOffdeviceUtils.copy(new BufferedInputStream(
-                    new FileInputStream(decodedSpec.mFile)), new BufferedOutputStream(dstStream));
+            try (
+                final InputStream input = getFileInputStream(decodedSpec.mFile);
+                final OutputStream output = new BufferedOutputStream(
+                        getFileOutputStreamOrStdOut(mArgs[1]))
+            ) {
+                BinaryDictOffdeviceUtils.copy(input, output);
+            }
         }
     }
 }
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java
index 7435fa7d62e197bc0483301702aefed64d7f4d6e..bdec4476114ee2cc001f2b6ec643469b8b2d7028 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java
@@ -23,13 +23,16 @@ import com.android.inputmethod.latin.makedict.ProbabilityInfo;
 import com.android.inputmethod.latin.makedict.WeightedString;
 import com.android.inputmethod.latin.makedict.WordProperty;
 
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.io.BufferedInputStream;
 import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
+import java.io.BufferedWriter;
+import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.Writer;
+import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.TreeSet;
@@ -38,10 +41,6 @@ import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
 /**
  * Reads and writes XML files for a FusionDictionary.
  *
@@ -57,8 +56,6 @@ public class XmlDictInputOutput {
     private static final String WORD_ATTR = "word";
     private static final String NOT_A_WORD_ATTR = "not_a_word";
 
-    private static final String OPTIONS_KEY = "options";
-
     /**
      * SAX handler for a unigram XML file.
      */
@@ -120,7 +117,6 @@ public class XmlDictInputOutput {
                     final String attrName = attrs.getLocalName(attrIndex);
                     attributes.put(attrName, attrs.getValue(attrIndex));
                 }
-                final String optionsString = attributes.get(OPTIONS_KEY);
                 mDictionary = new FusionDictionary(new PtNodeArray(),
                         new DictionaryOptions(attributes));
             } else {
@@ -244,14 +240,13 @@ public class XmlDictInputOutput {
         protected int getValueFromFreqString(final String freqString) {
             if (WHITELIST_MARKER.equals(freqString)) {
                 return WHITELIST_FREQ_VALUE;
-            } else {
-                final int intValue = super.getValueFromFreqString(freqString);
-                if (intValue < MIN_FREQ || intValue > MAX_FREQ) {
-                    throw new RuntimeException("Shortcut freq out of range. Accepted range is "
-                            + MIN_FREQ + ".." + MAX_FREQ);
-                }
-                return intValue;
             }
+            final int intValue = super.getValueFromFreqString(freqString);
+            if (intValue < MIN_FREQ || intValue > MAX_FREQ) {
+                throw new RuntimeException("Shortcut freq out of range. Accepted range is "
+                        + MIN_FREQ + ".." + MAX_FREQ);
+            }
+            return intValue;
         }
 
         // As per getAssocMap(), this never returns null.
@@ -269,23 +264,12 @@ public class XmlDictInputOutput {
      * @return true if the file is in the unigram XML format, false otherwise
      */
     public static boolean isXmlUnigramDictionary(final String filename) {
-        BufferedReader reader = null;
-        try {
-            reader = new BufferedReader(new FileReader(new File(filename)));
+        try (final BufferedReader reader = new BufferedReader(
+                new InputStreamReader(new FileInputStream(filename), "UTF-8"))) {
             final String firstLine = reader.readLine();
             return firstLine.matches("^\\s*<wordlist .*>\\s*$");
-        } catch (FileNotFoundException e) {
+        } catch (final IOException e) {
             return false;
-        } catch (IOException e) {
-            return false;
-        } finally {
-            if (reader != null) {
-                try {
-                    reader.close();
-                } catch (IOException e) {
-                    // do nothing
-                }
-            }
         }
     }
 
@@ -300,8 +284,8 @@ public class XmlDictInputOutput {
      * @param bigrams the file to read the bigrams from, or null.
      * @return the in-memory representation of the dictionary.
      */
-    public static FusionDictionary readDictionaryXml(final InputStream unigrams,
-            final InputStream shortcuts, final InputStream bigrams)
+    public static FusionDictionary readDictionaryXml(final BufferedInputStream unigrams,
+            final BufferedInputStream shortcuts, final BufferedInputStream bigrams)
             throws SAXException, IOException, ParserConfigurationException {
         final SAXParserFactory factory = SAXParserFactory.newInstance();
         factory.setNamespaceAware(true);
@@ -350,8 +334,8 @@ public class XmlDictInputOutput {
      * @param destination a destination stream to write to.
      * @param dict the dictionary to write.
      */
-    public static void writeDictionaryXml(Writer destination, FusionDictionary dict)
-            throws IOException {
+    public static void writeDictionaryXml(final BufferedWriter destination,
+            final FusionDictionary dict) throws IOException {
         final TreeSet<WordProperty> wordPropertiesInDict = new TreeSet<>();
         for (WordProperty wordProperty : dict) {
             wordPropertiesInDict.add(wordProperty);
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 fccb654b0a04b87561dfef6ddb88e825fc384281..0236a446d6b283ad51888c2d469ae10893c51f01 100644
--- a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
+++ b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
@@ -62,13 +62,13 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase {
 
         final File dst = File.createTempFile("testGetRawDict", ".tmp");
         dst.deleteOnExit();
-
-        final OutputStream out = Compress.getCompressedStream(
+        try (final OutputStream out = Compress.getCompressedStream(
                 Compress.getCompressedStream(
                         Compress.getCompressedStream(
-                                new BufferedOutputStream(new FileOutputStream(dst)))));
-        final DictEncoder dictEncoder = new Ver2DictEncoder(out);
-        dictEncoder.writeDictionary(dict, new FormatOptions(2, false));
+                                new BufferedOutputStream(new FileOutputStream(dst)))))) {
+            final DictEncoder dictEncoder = new Ver2DictEncoder(out);
+            dictEncoder.writeDictionary(dict, new FormatOptions(2, false));
+        }
 
         // Test for an actually compressed dictionary and its contents
         final BinaryDictOffdeviceUtils.DecoderChainSpec decodeSpec =
@@ -96,11 +96,11 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase {
         // Randomly create some 4k file containing garbage
         final File dst = File.createTempFile("testGetRawDict", ".tmp");
         dst.deleteOnExit();
-        final OutputStream out = new BufferedOutputStream(new FileOutputStream(dst));
-        for (int i = 0; i < 1024; ++i) {
-            out.write(0x12345678);
+        try (final OutputStream out = new BufferedOutputStream(new FileOutputStream(dst))) {
+            for (int i = 0; i < 1024; ++i) {
+                out.write(0x12345678);
+            }
         }
-        out.close();
 
         // Test that a random data file actually fails
         assertNull("Wrongly identified data file",
@@ -108,12 +108,12 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase {
 
         final File gzDst = File.createTempFile("testGetRawDict", ".tmp");
         gzDst.deleteOnExit();
-        final OutputStream gzOut =
-                Compress.getCompressedStream(new BufferedOutputStream(new FileOutputStream(gzDst)));
-        for (int i = 0; i < 1024; ++i) {
-            gzOut.write(0x12345678);
+        try (final OutputStream gzOut = Compress.getCompressedStream(
+                new BufferedOutputStream(new FileOutputStream(gzDst)))) {
+            for (int i = 0; i < 1024; ++i) {
+                gzOut.write(0x12345678);
+            }
         }
-        gzOut.close();
 
         // Test that a compressed random data file actually fails
         assertNull("Wrongly identified data file",