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 }