View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.io;
18  
19  import static org.apache.commons.io.IOUtils.EOF;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.InputStreamReader;
25  import java.io.OutputStream;
26  import java.io.OutputStreamWriter;
27  import java.io.Reader;
28  import java.io.StringReader;
29  import java.io.Writer;
30  import java.nio.charset.Charset;
31  
32  import org.apache.commons.io.IOUtils.ScratchChars;
33  
34  /**
35   * This class provides static utility methods for buffered
36   * copying between sources ({@link InputStream}, {@link Reader},
37   * {@link String} and {@code byte[]}) and destinations
38   * ({@link OutputStream}, {@link Writer}, {@link String} and
39   * {@code byte[]}).
40   * <p>
41   * Unless otherwise noted, these {@code copy} methods do <em>not</em>
42   * flush or close the streams. Often doing so would require making non-portable
43   * assumptions about the streams' origin and further use. This means that both
44   * streams' {@code close()} methods must be called after copying. if one
45   * omits this step, then the stream resources (sockets, file descriptors) are
46   * released when the associated Stream is garbage-collected. It is not a good
47   * idea to rely on this mechanism. For a good overview of the distinction
48   * between "memory management" and "resource management", see
49   * <a href="https://www.unixreview.com/articles/1998/9804/9804ja/ja.htm">this
50   * UnixReview article</a>.
51   * <p>
52   * For byte-to-char methods, a {@code copy} variant allows the encoding
53   * to be selected (otherwise the platform default is used). We would like to
54   * encourage you to always specify the encoding because relying on the platform
55   * default can lead to unexpected results.
56   * <p>
57   * We don't provide special variants for the {@code copy} methods that
58   * let you specify the buffer size because in modern VMs the impact on speed
59   * seems to be minimal. We're using a default buffer size of 4 KB.
60   * <p>
61   * The {@code copy} methods use an internal buffer when copying. It is
62   * therefore advisable <em>not</em> to deliberately wrap the stream arguments
63   * to the {@code copy} methods in {@code Buffered*} streams. For
64   * example, don't do the following:
65   * <pre>
66   *  copy( new BufferedInputStream( in ), new BufferedOutputStream( out ) );
67   *  </pre>
68   * The rationale is as follows:
69   * <p>
70   * Imagine that an InputStream's read() is a very expensive operation, which
71   * would usually suggest wrapping in a BufferedInputStream. The
72   * BufferedInputStream works by issuing infrequent
73   * {@link InputStream#read(byte[] b, int off, int len)} requests on the
74   * underlying InputStream, to fill an internal buffer, from which further
75   * {@code read} requests can inexpensively get their data (until the buffer
76   * runs out).
77   * <p>
78   * However, the {@code copy} methods do the same thing, keeping an
79   * internal buffer, populated by
80   * {@link InputStream#read(byte[] b, int off, int len)} requests. Having two
81   * buffers (or three if the destination stream is also buffered) is pointless,
82   * and the unnecessary buffer management hurts performance slightly (about 3%,
83   * according to some simple experiments).
84   * <p>
85   * Behold, intrepid explorers; a map of this class:
86   * <pre>
87   *       Method      Input               Output          Dependency
88   *       ------      -----               ------          -------
89   * 1     copy        InputStream         OutputStream    (primitive)
90   * 2     copy        Reader              Writer          (primitive)
91   *
92   * 3     copy        InputStream         Writer          2
93   *
94   * 4     copy        Reader              OutputStream    2
95   *
96   * 5     copy        String              OutputStream    2
97   * 6     copy        String              Writer          (trivial)
98   *
99   * 7     copy        byte[]              Writer          3
100  * 8     copy        byte[]              OutputStream    (trivial)
101  * </pre>
102  * <p>
103  * Note that only the first two methods shuffle bytes; the rest use these
104  * two, or (if possible) copy using native Java copy methods. As there are
105  * method variants to specify the encoding, each row may
106  * correspond to up to 2 methods.
107  * <p>
108  * Provenance: Excalibur.
109  *
110  * @deprecated Use IOUtils. Will be removed in 3.0.
111  *  Methods renamed to IOUtils.write() or IOUtils.copy().
112  *  Null handling behavior changed in IOUtils (null data does not
113  *  throw NullPointerException).
114  */
115 @Deprecated
116 public class CopyUtils {
117 
118     /**
119      * Copies bytes from a {@code byte[]} to an {@link OutputStream}.
120      *
121      * @param input the byte array to read from.
122      * @param output the {@link OutputStream} to write to.
123      * @throws IOException In case of an I/O problem.
124      */
125     public static void copy(final byte[] input, final OutputStream output) throws IOException {
126         output.write(input);
127     }
128 
129     /**
130      * Copies and convert bytes from a {@code byte[]} to chars on a
131      * {@link Writer}.
132      * The platform's default encoding is used for the byte-to-char conversion.
133      *
134      * @param input the byte array to read from.
135      * @param output the {@link Writer} to write to.
136      * @throws IOException In case of an I/O problem.
137      * @deprecated Use {@link #copy(byte[], Writer, String)} instead.
138      */
139     @Deprecated
140     public static void copy(final byte[] input, final Writer output) throws IOException {
141         final ByteArrayInputStream inputStream = new ByteArrayInputStream(input);
142         copy(inputStream, output);
143     }
144 
145     /**
146      * Copies and convert bytes from a {@code byte[]} to chars on a
147      * {@link Writer}, using the specified encoding.
148      *
149      * @param input the byte array to read from.
150      * @param output the {@link Writer} to write to.
151      * @param encoding The name of a supported character encoding. See the
152      * <a href="https://www.iana.org/assignments/character-sets">IANA
153      * Charset Registry</a> for a list of valid encoding types.
154      * @throws IOException In case of an I/O problem.
155      */
156     public static void copy(final byte[] input, final Writer output, final String encoding) throws IOException {
157         final ByteArrayInputStream inputStream = new ByteArrayInputStream(input);
158         copy(inputStream, output, encoding);
159     }
160 
161     /**
162      * Copies bytes from an {@link InputStream} to an
163      * {@link OutputStream}.
164      *
165      * @param input the {@link InputStream} to read from.
166      * @param output the {@link OutputStream} to write to.
167      * @return the number of bytes copied.
168      * @throws IOException In case of an I/O problem.
169      */
170     public static int copy(final InputStream input, final OutputStream output) throws IOException {
171         final byte[] buffer = IOUtils.byteArray();
172         int count = 0;
173         int n;
174         while (EOF != (n = input.read(buffer))) {
175             output.write(buffer, 0, n);
176             count += n;
177         }
178         return count;
179     }
180 
181     /**
182      * Copies and convert bytes from an {@link InputStream} to chars on a
183      * {@link Writer}.
184      * <p>
185      * This method uses the virtual machine's {@linkplain Charset#defaultCharset() default charset} for byte-to-char conversion.
186      * </p>
187      *
188      * @param input the {@link InputStream} to read from.
189      * @param output the {@link Writer} to write to.
190      * @throws IOException In case of an I/O problem.
191      * @deprecated Use {@link #copy(InputStream, Writer, String)} instead.
192      */
193     @Deprecated
194     public static void copy(
195             final InputStream input,
196             final Writer output)
197                 throws IOException {
198         // make explicit the dependency on the default encoding
199         final InputStreamReader in = new InputStreamReader(input, Charset.defaultCharset());
200         copy(in, output);
201     }
202 
203     /**
204      * Copies and convert bytes from an {@link InputStream} to chars on a
205      * {@link Writer}, using the specified encoding.
206      *
207      * @param input the {@link InputStream} to read from.
208      * @param output the {@link Writer} to write to.
209      * @param encoding The name of a supported character encoding. See the
210      * <a href="https://www.iana.org/assignments/character-sets">IANA
211      * Charset Registry</a> for a list of valid encoding types.
212      * @throws IOException In case of an I/O problem.
213      */
214     public static void copy(
215             final InputStream input,
216             final Writer output,
217             final String encoding)
218                 throws IOException {
219         final InputStreamReader in = new InputStreamReader(input, encoding);
220         copy(in, output);
221     }
222 
223     /**
224      * Serialize chars from a {@link Reader} to bytes on an
225      * {@link OutputStream}, and flush the {@link OutputStream}.
226      * <p>
227      * This method uses the virtual machine's {@linkplain Charset#defaultCharset() default charset} for byte-to-char conversion.
228      * </p>
229      *
230      * @param input the {@link Reader} to read from.
231      * @param output the {@link OutputStream} to write to.
232      * @throws IOException In case of an I/O problem.
233      * @deprecated Use {@link #copy(Reader, OutputStream, String)} instead.
234      */
235     @Deprecated
236     public static void copy(
237             final Reader input,
238             final OutputStream output)
239                 throws IOException {
240         // make explicit the dependency on the default encoding
241         final OutputStreamWriter out = new OutputStreamWriter(output, Charset.defaultCharset());
242         copy(input, out);
243         // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
244         // have to flush here.
245         out.flush();
246     }
247 
248     /**
249      * Serialize chars from a {@link Reader} to bytes on an
250      * {@link OutputStream}, and flush the {@link OutputStream}.
251      *
252      * @param input the {@link Reader} to read from.
253      * @param output the {@link OutputStream} to write to.
254      * @param encoding The name of a supported character encoding. See the
255      * <a href="https://www.iana.org/assignments/character-sets">IANA
256      * Charset Registry</a> for a list of valid encoding types.
257      * @throws IOException In case of an I/O problem.
258      * @since 2.5
259      */
260     public static void copy(
261             final Reader input,
262             final OutputStream output,
263             final String encoding)
264                 throws IOException {
265         final OutputStreamWriter out = new OutputStreamWriter(output, encoding);
266         copy(input, out);
267         // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
268         // have to flush here.
269         out.flush();
270     }
271 
272     /**
273      * Copies chars from a {@link Reader} to a {@link Writer}.
274      *
275      * @param input the {@link Reader} to read from.
276      * @param output the {@link Writer} to write to.
277      * @return the number of characters copied.
278      * @throws IOException In case of an I/O problem.
279      */
280     public static int copy(
281             final Reader input,
282             final Writer output)
283                 throws IOException {
284         try (ScratchChars scratch = IOUtils.ScratchChars.get()) {
285             final char[] buffer = scratch.array();
286             int count = 0;
287             int n;
288             while (EOF != (n = input.read(buffer))) {
289                 output.write(buffer, 0, n);
290                 count += n;
291             }
292             return count;
293         }
294     }
295 
296     /**
297      * Serialize chars from a {@link String} to bytes on an
298      * {@link OutputStream}, and
299      * flush the {@link OutputStream}.
300      * <p>
301      * This method uses the virtual machine's {@linkplain Charset#defaultCharset() default charset} for byte-to-char conversion.
302      * </p>
303      *
304      * @param input the {@link String} to read from.
305      * @param output the {@link OutputStream} to write to.
306      * @throws IOException In case of an I/O problem.
307      * @deprecated Use {@link #copy(String, OutputStream, String)} instead.
308      */
309     @Deprecated
310     public static void copy(
311             final String input,
312             final OutputStream output)
313                 throws IOException {
314         final StringReader in = new StringReader(input);
315         // make explicit the dependency on the default encoding
316         final OutputStreamWriter out = new OutputStreamWriter(output, Charset.defaultCharset());
317         copy(in, out);
318         // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
319         // have to flush here.
320         out.flush();
321     }
322 
323     /**
324      * Serialize chars from a {@link String} to bytes on an
325      * {@link OutputStream}, and
326      * flush the {@link OutputStream}.
327      *
328      * @param input the {@link String} to read from.
329      * @param output the {@link OutputStream} to write to.
330      * @param encoding The name of a supported character encoding. See the
331      * <a href="https://www.iana.org/assignments/character-sets">IANA
332      * Charset Registry</a> for a list of valid encoding types.
333      * @throws IOException In case of an I/O problem.
334      * @since 2.5
335      */
336     public static void copy(
337             final String input,
338             final OutputStream output,
339             final String encoding)
340                 throws IOException {
341         final StringReader in = new StringReader(input);
342         final OutputStreamWriter out = new OutputStreamWriter(output, encoding);
343         copy(in, out);
344         // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
345         // have to flush here.
346         out.flush();
347     }
348 
349     /**
350      * Copies chars from a {@link String} to a {@link Writer}.
351      *
352      * @param input the {@link String} to read from.
353      * @param output the {@link Writer} to write to.
354      * @throws IOException In case of an I/O problem.
355      */
356     public static void copy(final String input, final Writer output)
357                 throws IOException {
358         output.write(input);
359     }
360 
361     /**
362      * Instances should NOT be constructed in standard programming.
363      *
364      * @deprecated TODO Make private in 3.0.
365      */
366     @Deprecated
367     public CopyUtils() {
368         // empty
369     }
370 
371 }