Does Groovy File.append(String) closes stream automatically?

Solution 1:

After taking a look at the groovy source, yes it does.

For the details:

    // ResourceGroovyMethods.java line 870
    /**
     * Append the text at the end of the File without writing a BOM.
     *
     * @param file a File
     * @param text the text to append at the end of the File
     * @throws IOException if an IOException occurs.
     * @since 1.0
     */
    public static void append(File file, Object text) throws IOException {
        append(file, text, false);
    }

  
    // ResourceGroovyMethods.java line 882
    /**
     * Append the text at the end of the File.  If the default
     * charset is "UTF-16BE" or "UTF-16LE" (or an equivalent alias) and
     * <code>writeBom</code> is <code>true</code>, the requisite byte order
     * mark is written to the file before the text.
     *
     * @param file     a File
     * @param text     the text to append at the end of the File
     * @param writeBom whether to write a BOM
     * @throws IOException if an IOException occurs.
     * @since 2.5.0
     */
    public static void append(File file, Object text, boolean writeBom) throws IOException {
        append(file, text, Charset.defaultCharset().name(), writeBom);
    }

    // ResourceGroovyMethods.java line 1027
    /**
     * Append the text at the end of the File, using a specified encoding.  If
     * the given charset is "UTF-16BE" or "UTF-16LE" (or an equivalent alias),
     * <code>writeBom</code> is <code>true</code>, and the file doesn't already
     * exist, the requisite byte order mark is written to the file before the
     * text is appended.
     *
     * @param file     a File
     * @param text     the text to append at the end of the File
     * @param charset  the charset used
     * @param writeBom whether to write a BOM
     * @throws IOException if an IOException occurs.
     * @since 2.5.0
     */
    public static void append(File file, Object text, String charset, boolean writeBom) throws IOException {
        Writer writer = null;
        try {
            boolean shouldWriteBom = writeBom && !file.exists();
            FileOutputStream out = new FileOutputStream(file, true);
            if (shouldWriteBom) {
                IOGroovyMethods.writeUTF16BomIfRequired(out, charset);
            }
            writer = new OutputStreamWriter(out, charset);
            InvokerHelper.write(writer, text);
            writer.flush();

            Writer temp = writer;
            writer = null;
            temp.close();
        } finally {
            closeWithWarning(writer);
        }
    }


    // DefaultGroovyMethodsSupport.java line 119
    /**
     * Close the Closeable. Logging a warning if any problems occur.
     *
     * @param closeable the thing to close
     */
    public static void closeWithWarning(Closeable closeable) {
        tryClose(closeable, true); // ignore result
    }

    // DefaultGroovyMethodsSupport.java line 128
    /**
     * Attempts to close the closeable returning rather than throwing
     * any Exception that may occur.
     *
     * @param closeable the thing to close
     * @param logWarning if true will log a warning if an exception occurs
     * @return throwable Exception from the close method, else null
     */
    static Throwable tryClose(AutoCloseable closeable, boolean logWarning) {
        Throwable thrown = null;
        if (closeable != null) {
            try {
                closeable.close();
            } catch (Exception e) {
                thrown = e;
                if (logWarning) {
                    LOG.warning("Caught exception during close(): " + e);
                }
            }
        }
        return thrown;
    }

where your file.append(string) call will be handled by the public static void append(File file, Object text) method.

Following the code we can see that the writer is closed in a finally block which means that the close operation will always be run, exceptions or not.