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