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 * @param input the byte array to read from
121 * @param output the {@link OutputStream} to write to
122 * @throws IOException In case of an I/O problem
123 */
124 public static void copy(final byte[] input, final OutputStream output) throws IOException {
125 output.write(input);
126 }
127
128 /**
129 * Copies and convert bytes from a {@code byte[]} to chars on a
130 * {@link Writer}.
131 * The platform's default encoding is used for the byte-to-char conversion.
132 *
133 * @param input the byte array to read from
134 * @param output the {@link Writer} to write to
135 * @throws IOException In case of an I/O problem
136 * @deprecated Use {@link #copy(byte[], Writer, String)} instead
137 */
138 @Deprecated
139 public static void copy(final byte[] input, final Writer output) throws IOException {
140 final ByteArrayInputStream inputStream = new ByteArrayInputStream(input);
141 copy(inputStream, output);
142 }
143
144 /**
145 * Copies and convert bytes from a {@code byte[]} to chars on a
146 * {@link Writer}, using the specified encoding.
147 *
148 * @param input the byte array to read from
149 * @param output the {@link Writer} to write to
150 * @param encoding The name of a supported character encoding. See the
151 * <a href="https://www.iana.org/assignments/character-sets">IANA
152 * Charset Registry</a> for a list of valid encoding types.
153 * @throws IOException In case of an I/O problem
154 */
155 public static void copy(final byte[] input, final Writer output, final String encoding) throws IOException {
156 final ByteArrayInputStream inputStream = new ByteArrayInputStream(input);
157 copy(inputStream, output, encoding);
158 }
159
160 /**
161 * Copies bytes from an {@link InputStream} to an
162 * {@link OutputStream}.
163 *
164 * @param input the {@link InputStream} to read from
165 * @param output the {@link OutputStream} to write to
166 * @return the number of bytes copied
167 * @throws IOException In case of an I/O problem
168 */
169 public static int copy(final InputStream input, final OutputStream output) throws IOException {
170 final byte[] buffer = IOUtils.byteArray();
171 int count = 0;
172 int n;
173 while (EOF != (n = input.read(buffer))) {
174 output.write(buffer, 0, n);
175 count += n;
176 }
177 return count;
178 }
179
180 /**
181 * Copies and convert bytes from an {@link InputStream} to chars on a
182 * {@link Writer}.
183 * <p>
184 * This method uses the virtual machine's {@linkplain Charset#defaultCharset() default charset} for byte-to-char conversion.
185 * </p>
186 *
187 * @param input the {@link InputStream} to read from
188 * @param output the {@link Writer} to write to
189 * @throws IOException In case of an I/O problem
190 * @deprecated Use {@link #copy(InputStream, Writer, String)} instead
191 */
192 @Deprecated
193 public static void copy(
194 final InputStream input,
195 final Writer output)
196 throws IOException {
197 // make explicit the dependency on the default encoding
198 final InputStreamReader in = new InputStreamReader(input, Charset.defaultCharset());
199 copy(in, output);
200 }
201
202 /**
203 * Copies and convert bytes from an {@link InputStream} to chars on a
204 * {@link Writer}, using the specified encoding.
205 *
206 * @param input the {@link InputStream} to read from
207 * @param output the {@link Writer} to write to
208 * @param encoding The name of a supported character encoding. See the
209 * <a href="https://www.iana.org/assignments/character-sets">IANA
210 * Charset Registry</a> for a list of valid encoding types.
211 * @throws IOException In case of an I/O problem
212 */
213 public static void copy(
214 final InputStream input,
215 final Writer output,
216 final String encoding)
217 throws IOException {
218 final InputStreamReader in = new InputStreamReader(input, encoding);
219 copy(in, output);
220 }
221
222 /**
223 * Serialize chars from a {@link Reader} to bytes on an
224 * {@link OutputStream}, and flush the {@link OutputStream}.
225 * <p>
226 * This method uses the virtual machine's {@linkplain Charset#defaultCharset() default charset} for byte-to-char conversion.
227 * </p>
228 *
229 * @param input the {@link Reader} to read from
230 * @param output the {@link OutputStream} to write to
231 * @throws IOException In case of an I/O problem
232 * @deprecated Use {@link #copy(Reader, OutputStream, String)} instead
233 */
234 @Deprecated
235 public static void copy(
236 final Reader input,
237 final OutputStream output)
238 throws IOException {
239 // make explicit the dependency on the default encoding
240 final OutputStreamWriter out = new OutputStreamWriter(output, Charset.defaultCharset());
241 copy(input, out);
242 // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
243 // have to flush here.
244 out.flush();
245 }
246
247 /**
248 * Serialize chars from a {@link Reader} to bytes on an
249 * {@link OutputStream}, and flush the {@link OutputStream}.
250 *
251 * @param input the {@link Reader} to read from
252 * @param output the {@link OutputStream} to write to
253 * @param encoding The name of a supported character encoding. See the
254 * <a href="https://www.iana.org/assignments/character-sets">IANA
255 * Charset Registry</a> for a list of valid encoding types.
256 * @throws IOException In case of an I/O problem
257 * @since 2.5
258 */
259 public static void copy(
260 final Reader input,
261 final OutputStream output,
262 final String encoding)
263 throws IOException {
264 final OutputStreamWriter out = new OutputStreamWriter(output, encoding);
265 copy(input, out);
266 // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
267 // have to flush here.
268 out.flush();
269 }
270
271 /**
272 * Copies chars from a {@link Reader} to a {@link Writer}.
273 *
274 * @param input the {@link Reader} to read from
275 * @param output the {@link Writer} to write to
276 * @return the number of characters copied
277 * @throws IOException In case of an I/O problem
278 */
279 public static int copy(
280 final Reader input,
281 final Writer output)
282 throws IOException {
283 try (ScratchChars scratch = IOUtils.ScratchChars.get()) {
284 final char[] buffer = scratch.array();
285 int count = 0;
286 int n;
287 while (EOF != (n = input.read(buffer))) {
288 output.write(buffer, 0, n);
289 count += n;
290 }
291 return count;
292 }
293 }
294
295 /**
296 * Serialize chars from a {@link String} to bytes on an
297 * {@link OutputStream}, and
298 * flush the {@link OutputStream}.
299 * <p>
300 * This method uses the virtual machine's {@linkplain Charset#defaultCharset() default charset} for byte-to-char conversion.
301 * </p>
302 *
303 * @param input the {@link String} to read from
304 * @param output the {@link OutputStream} to write to
305 * @throws IOException In case of an I/O problem
306 * @deprecated Use {@link #copy(String, OutputStream, String)} instead
307 */
308 @Deprecated
309 public static void copy(
310 final String input,
311 final OutputStream output)
312 throws IOException {
313 final StringReader in = new StringReader(input);
314 // make explicit the dependency on the default encoding
315 final OutputStreamWriter out = new OutputStreamWriter(output, Charset.defaultCharset());
316 copy(in, out);
317 // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
318 // have to flush here.
319 out.flush();
320 }
321
322 /**
323 * Serialize chars from a {@link String} to bytes on an
324 * {@link OutputStream}, and
325 * flush the {@link OutputStream}.
326 *
327 * @param input the {@link String} to read from
328 * @param output the {@link OutputStream} to write to
329 * @param encoding The name of a supported character encoding. See the
330 * <a href="https://www.iana.org/assignments/character-sets">IANA
331 * Charset Registry</a> for a list of valid encoding types.
332 * @throws IOException In case of an I/O problem
333 * @since 2.5
334 */
335 public static void copy(
336 final String input,
337 final OutputStream output,
338 final String encoding)
339 throws IOException {
340 final StringReader in = new StringReader(input);
341 final OutputStreamWriter out = new OutputStreamWriter(output, encoding);
342 copy(in, out);
343 // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
344 // have to flush here.
345 out.flush();
346 }
347
348 /**
349 * Copies chars from a {@link String} to a {@link Writer}.
350 *
351 * @param input the {@link String} to read from
352 * @param output the {@link Writer} to write to
353 * @throws IOException In case of an I/O problem
354 */
355 public static void copy(final String input, final Writer output)
356 throws IOException {
357 output.write(input);
358 }
359
360 /**
361 * Instances should NOT be constructed in standard programming.
362 *
363 * @deprecated TODO Make private in 3.0.
364 */
365 @Deprecated
366 public CopyUtils() {
367 // empty
368 }
369
370 }