    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.io;
    018
    019import java.io.ByteArrayInputStream;
    020import java.io.IOException;
    021import java.io.InputStream;
    022import java.io.InputStreamReader;
    023import java.io.OutputStream;
    024import java.io.OutputStreamWriter;
    025import java.io.Reader;
    026import java.io.StringReader;
    027import java.io.Writer;
    028import java.nio.charset.Charset;
    029
    030/**
    031 * This class provides static utility methods for buffered
    032 * copying between sources (<code>InputStream</code>, <code>Reader</code>,
    033 * <code>String</code> and <code>byte[]</code>) and destinations
    034 * (<code>OutputStream</code>, <code>Writer</code>, <code>String</code> and
    035 * <code>byte[]</code>).
    036 * <p>
    037 * Unless otherwise noted, these <code>copy</code> methods do <em>not</em>
    038 * flush or close the streams. Often doing so would require making non-portable
    039 * assumptions about the streams' origin and further use. This means that both
    040 * streams' <code>close()</code> methods must be called after copying. if one
    041 * omits this step, then the stream resources (sockets, file descriptors) are
    042 * released when the associated Stream is garbage-collected. It is not a good
    043 * idea to rely on this mechanism. For a good overview of the distinction
    044 * between "memory management" and "resource management", see
    045 * <a href="http://www.unixreview.com/articles/1998/9804/9804ja/ja.htm">this
    046 * UnixReview article</a>.
    047 * <p>
    048 * For byte-to-char methods, a <code>copy</code> variant allows the encoding
    049 * to be selected (otherwise the platform default is used). We would like to
    050 * encourage you to always specify the encoding because relying on the platform
    051 * default can lead to unexpected results.
    052 * <p>
    053 * We don't provide special variants for the <code>copy</code> methods that
    054 * let you specify the buffer size because in modern VMs the impact on speed
    055 * seems to be minimal. We're using a default buffer size of 4 KB.
    056 * <p>
    057 * The <code>copy</code> methods use an internal buffer when copying. It is
    058 * therefore advisable <em>not</em> to deliberately wrap the stream arguments
    059 * to the <code>copy</code> methods in <code>Buffered*</code> streams. For
    060 * example, don't do the following:
    061 * <pre>
    062 *  copy( new BufferedInputStream( in ), new BufferedOutputStream( out ) );
    063 *  </pre>
    064 * The rationale is as follows:
    065 * <p>
    066 * Imagine that an InputStream's read() is a very expensive operation, which
    067 * would usually suggest wrapping in a BufferedInputStream. The
    068 * BufferedInputStream works by issuing infrequent
    069 * {@link java.io.InputStream#read(byte[] b, int off, int len)} requests on the
    070 * underlying InputStream, to fill an internal buffer, from which further
    071 * <code>read</code> requests can inexpensively get their data (until the buffer
    072 * runs out).
    073 * <p>
    074 * However, the <code>copy</code> methods do the same thing, keeping an
    075 * internal buffer, populated by
    076 * {@link InputStream#read(byte[] b, int off, int len)} requests. Having two
    077 * buffers (or three if the destination stream is also buffered) is pointless,
    078 * and the unnecessary buffer management hurts performance slightly (about 3%,
    079 * according to some simple experiments).
    080 * <p>
    081 * Behold, intrepid explorers; a map of this class:
    082 * <pre>
    083 *       Method      Input               Output          Dependency
    084 *       ------      -----               ------          -------
    085 * 1     copy        InputStream         OutputStream    (primitive)
    086 * 2     copy        Reader              Writer          (primitive)
    087 *
    088 * 3     copy        InputStream         Writer          2
    089 *
    090 * 4     copy        Reader              OutputStream    2
    091 *
    092 * 5     copy        String              OutputStream    2
    093 * 6     copy        String              Writer          (trivial)
    094 *
    095 * 7     copy        byte[]              Writer          3
    096 * 8     copy        byte[]              OutputStream    (trivial)
    097 * </pre>
    098 * <p>
    099 * Note that only the first two methods shuffle bytes; the rest use these
    100 * two, or (if possible) copy using native Java copy methods. As there are
    101 * method variants to specify the encoding, each row may
    102 * correspond to up to 2 methods.
    103 * <p>
    104 * Origin of code: Excalibur.
    105 *
    106 * @deprecated Use IOUtils. Will be removed in 2.0.
    107 *  Methods renamed to IOUtils.write() or IOUtils.copy().
    108 *  Null handling behavior changed in IOUtils (null data does not
    109 *  throw NullPointerException).
    110 */
    111@Deprecated
    112public class CopyUtils {
    113
    114    /**
    115     * The default size of the buffer.
    116     */
    117    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
    118
    119    /**
    120     * Instances should NOT be constructed in standard programming.
    121     */
    122    public CopyUtils() { }
    123
    124    // ----------------------------------------------------------------
    125    // byte[] -> OutputStream
    126    // ----------------------------------------------------------------
    127
    128    /**
    129     * Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
    130     * @param input the byte array to read from
    131     * @param output the <code>OutputStream</code> to write to
    132     * @throws IOException In case of an I/O problem
    133     */
    134    public static void copy(final byte[] input, final OutputStream output)
    135            throws IOException {
    136        output.write(input);
    137    }
    138
    139    // ----------------------------------------------------------------
    140    // byte[] -> Writer
    141    // ----------------------------------------------------------------
    142
    143    /**
    144     * Copy and convert bytes from a <code>byte[]</code> to chars on a
    145     * <code>Writer</code>.
    146     * The platform's default encoding is used for the byte-to-char conversion.
    147     * @param input the byte array to read from
    148     * @param output the <code>Writer</code> to write to
    149     * @throws IOException In case of an I/O problem
    150     * @deprecated 2.5 use {@link #copy(byte[], Writer, String)} instead
    151     */
    152    @Deprecated
    153    public static void copy(final byte[] input, final Writer output)
    154            throws IOException {
    155        final ByteArrayInputStream in = new ByteArrayInputStream(input);
    156        copy(in, output);
    157    }
    158
    159
    160    /**
    161     * Copy and convert bytes from a <code>byte[]</code> to chars on a
    162     * <code>Writer</code>, using the specified encoding.
    163     * @param input the byte array to read from
    164     * @param output the <code>Writer</code> to write to
    165     * @param encoding The name of a supported character encoding. See the
    166     * <a href="http://www.iana.org/assignments/character-sets">IANA
    167     * Charset Registry</a> for a list of valid encoding types.
    168     * @throws IOException In case of an I/O problem
    169     */
    170    public static void copy(
    171            final byte[] input,
    172            final Writer output,
    173            final String encoding)
    174                throws IOException {
    175        final ByteArrayInputStream in = new ByteArrayInputStream(input);
    176        copy(in, output, encoding);
    177    }
    178
    179
    180    // ----------------------------------------------------------------
    181    // Core copy methods
    182    // ----------------------------------------------------------------
    183
    184    /**
    185     * Copy bytes from an <code>InputStream</code> to an
    186     * <code>OutputStream</code>.
    187     * @param input the <code>InputStream</code> to read from
    188     * @param output the <code>OutputStream</code> to write to
    189     * @return the number of bytes copied
    190     * @throws IOException In case of an I/O problem
    191     */
    192    public static int copy(
    193            final InputStream input,
    194            final OutputStream output)
    195                throws IOException {
    196        final byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
    197        int count = 0;
    198        int n = 0;
    199        while (-1 != (n = input.read(buffer))) {
    200            output.write(buffer, 0, n);
    201            count += n;
    202        }
    203        return count;
    204    }
    205
    206    // ----------------------------------------------------------------
    207    // Reader -> Writer
    208    // ----------------------------------------------------------------
    209
    210    /**
    211     * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
    212     * @param input the <code>Reader</code> to read from
    213     * @param output the <code>Writer</code> to write to
    214     * @return the number of characters copied
    215     * @throws IOException In case of an I/O problem
    216     */
    217    public static int copy(
    218            final Reader input,
    219            final Writer output)
    220                throws IOException {
    221        final char[] buffer = new char[DEFAULT_BUFFER_SIZE];
    222        int count = 0;
    223        int n = 0;
    224        while (-1 != (n = input.read(buffer))) {
    225            output.write(buffer, 0, n);
    226            count += n;
    227        }
    228        return count;
    229    }
    230
    231    // ----------------------------------------------------------------
    232    // InputStream -> Writer
    233    // ----------------------------------------------------------------
    234
    235    /**
    236     * Copy and convert bytes from an <code>InputStream</code> to chars on a
    237     * <code>Writer</code>.
    238     * The platform's default encoding is used for the byte-to-char conversion.
    239     * @param input the <code>InputStream</code> to read from
    240     * @param output the <code>Writer</code> to write to
    241     * @throws IOException In case of an I/O problem
    242     * @deprecated 2.5 use {@link #copy(InputStream, Writer, String)} instead
    243     */
    244    @Deprecated
    245    public static void copy(
    246            final InputStream input,
    247            final Writer output)
    248                throws IOException {
    249        // make explicit the dependency on the default encoding
    250        final InputStreamReader in = new InputStreamReader(input, Charset.defaultCharset());
    251        copy(in, output);
    252    }
    253
    254    /**
    255     * Copy and convert bytes from an <code>InputStream</code> to chars on a
    256     * <code>Writer</code>, using the specified encoding.
    257     * @param input the <code>InputStream</code> to read from
    258     * @param output the <code>Writer</code> to write to
    259     * @param encoding The name of a supported character encoding. See the
    260     * <a href="http://www.iana.org/assignments/character-sets">IANA
    261     * Charset Registry</a> for a list of valid encoding types.
    262     * @throws IOException In case of an I/O problem
    263     */
    264    public static void copy(
    265            final InputStream input,
    266            final Writer output,
    267            final String encoding)
    268                throws IOException {
    269        final InputStreamReader in = new InputStreamReader(input, encoding);
    270        copy(in, output);
    271    }
    272
    273
    274    // ----------------------------------------------------------------
    275    // Reader -> OutputStream
    276    // ----------------------------------------------------------------
    277
    278    /**
    279     * Serialize chars from a <code>Reader</code> to bytes on an
    280     * <code>OutputStream</code>, and flush the <code>OutputStream</code>.
    281     * Uses the default platform encoding.
    282     * @param input the <code>Reader</code> to read from
    283     * @param output the <code>OutputStream</code> to write to
    284     * @throws IOException In case of an I/O problem
    285     * @deprecated 2.5 use {@link #copy(Reader, OutputStream, String)} instead
    286     */
    287    @Deprecated
    288    public static void copy(
    289            final Reader input,
    290            final OutputStream output)
    291                throws IOException {
    292        // make explicit the dependency on the default encoding
    293        final OutputStreamWriter out = new OutputStreamWriter(output, Charset.defaultCharset());
    294        copy(input, out);
    295        // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
    296        // have to flush here.
    297        out.flush();
    298    }
    299
    300    /**
    301     * Serialize chars from a <code>Reader</code> to bytes on an
    302     * <code>OutputStream</code>, and flush the <code>OutputStream</code>.
    303     * @param input the <code>Reader</code> to read from
    304     * @param output the <code>OutputStream</code> to write to
    305     * @param encoding The name of a supported character encoding. See the
    306     * <a href="http://www.iana.org/assignments/character-sets">IANA
    307     * Charset Registry</a> for a list of valid encoding types.
    308     * @throws IOException In case of an I/O problem
    309     * @since 2.5
    310     */
    311    public static void copy(
    312            final Reader input,
    313            final OutputStream output,
    314            final String encoding)
    315                throws IOException {
    316        final OutputStreamWriter out = new OutputStreamWriter(output, encoding);
    317        copy(input, out);
    318        // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
    319        // have to flush here.
    320        out.flush();
    321    }
    322
    323    // ----------------------------------------------------------------
    324    // String -> OutputStream
    325    // ----------------------------------------------------------------
    326
    327    /**
    328     * Serialize chars from a <code>String</code> to bytes on an
    329     * <code>OutputStream</code>, and
    330     * flush the <code>OutputStream</code>.
    331     * Uses the platform default encoding.
    332     * @param input the <code>String</code> to read from
    333     * @param output the <code>OutputStream</code> to write to
    334     * @throws IOException In case of an I/O problem
    335     * @deprecated 2.5 use {@link #copy(String, OutputStream, String)} instead
    336     */
    337    @Deprecated
    338    public static void copy(
    339            final String input,
    340            final OutputStream output)
    341                throws IOException {
    342        final StringReader in = new StringReader(input);
    343        // make explicit the dependency on the default encoding
    344        final OutputStreamWriter out = new OutputStreamWriter(output, Charset.defaultCharset());
    345        copy(in, out);
    346        // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
    347        // have to flush here.
    348        out.flush();
    349    }
    350
    351    /**
    352     * Serialize chars from a <code>String</code> to bytes on an
    353     * <code>OutputStream</code>, and
    354     * flush the <code>OutputStream</code>.
    355     * @param input the <code>String</code> to read from
    356     * @param output the <code>OutputStream</code> to write to
    357     * @param encoding The name of a supported character encoding. See the
    358     * <a href="http://www.iana.org/assignments/character-sets">IANA
    359     * Charset Registry</a> for a list of valid encoding types.
    360     * @throws IOException In case of an I/O problem
    361     * @since 2.5
    362     */
    363    public static void copy(
    364            final String input,
    365            final OutputStream output,
    366            final String encoding)
    367                throws IOException {
    368        final StringReader in = new StringReader(input);
    369        final OutputStreamWriter out = new OutputStreamWriter(output, encoding);
    370        copy(in, out);
    371        // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
    372        // have to flush here.
    373        out.flush();
    374    }
    375
    376    // ----------------------------------------------------------------
    377    // String -> Writer
    378    // ----------------------------------------------------------------
    379
    380    /**
    381     * Copy chars from a <code>String</code> to a <code>Writer</code>.
    382     * @param input the <code>String</code> to read from
    383     * @param output the <code>Writer</code> to write to
    384     * @throws IOException In case of an I/O problem
    385     */
    386    public static void copy(final String input, final Writer output)
    387                throws IOException {
    388        output.write(input);
    389    }
    390
    391}