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 * http://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
18 package org.apache.commons.net.io;
19
20 import java.io.Closeable;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.io.Reader;
25 import java.io.Writer;
26 import java.net.Socket;
27
28 /***
29 * The Util class cannot be instantiated and stores short static convenience
30 * methods that are often quite useful.
31 * <p>
32 * <p>
33 * @see CopyStreamException
34 * @see CopyStreamListener
35 * @see CopyStreamAdapter
36 ***/
37
38 public final class Util
39 {
40 /**
41 * The default buffer size ({@value}) used by
42 * {@link #copyStream copyStream } and {@link #copyReader copyReader}
43 * and by the copyReader/copyStream methods if a zero or negative buffer size is supplied.
44 */
45 public static final int DEFAULT_COPY_BUFFER_SIZE = 1024;
46
47 // Cannot be instantiated
48 private Util()
49 { }
50
51
52 /***
53 * Copies the contents of an InputStream to an OutputStream using a
54 * copy buffer of a given size and notifies the provided
55 * CopyStreamListener of the progress of the copy operation by calling
56 * its bytesTransferred(long, int) method after each write to the
57 * destination. If you wish to notify more than one listener you should
58 * use a CopyStreamAdapter as the listener and register the additional
59 * listeners with the CopyStreamAdapter.
60 * <p>
61 * The contents of the InputStream are
62 * read until the end of the stream is reached, but neither the
63 * source nor the destination are closed. You must do this yourself
64 * outside of the method call. The number of bytes read/written is
65 * returned.
66 * <p>
67 * @param source The source InputStream.
68 * @param dest The destination OutputStream.
69 * @param bufferSize The number of bytes to buffer during the copy.
70 * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
71 * @param streamSize The number of bytes in the stream being copied.
72 * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
73 * @param listener The CopyStreamListener to notify of progress. If
74 * this parameter is null, notification is not attempted.
75 * @param flush Whether to flush the output stream after every
76 * write. This is necessary for interactive sessions that rely on
77 * buffered streams. If you don't flush, the data will stay in
78 * the stream buffer.
79 * @exception CopyStreamException If an error occurs while reading from the
80 * source or writing to the destination. The CopyStreamException
81 * will contain the number of bytes confirmed to have been
82 * transferred before an
83 * IOException occurred, and it will also contain the IOException
84 * that caused the error. These values can be retrieved with
85 * the CopyStreamException getTotalBytesTransferred() and
86 * getIOException() methods.
87 ***/
88 public static final long copyStream(InputStream source, OutputStream dest,
89 int bufferSize, long streamSize,
90 CopyStreamListener listener,
91 boolean flush)
92 throws CopyStreamException
93 {
94 int bytes;
95 long total = 0;
96 byte[] buffer = new byte[bufferSize >= 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE];
97
98 try
99 {
100 while ((bytes = source.read(buffer)) != -1)
101 {
102 // Technically, some read(byte[]) methods may return 0 and we cannot
103 // accept that as an indication of EOF.
104
105 if (bytes == 0)
106 {
107 bytes = source.read();
108 if (bytes < 0) {
109 break;
110 }
111 dest.write(bytes);
112 if(flush) {
113 dest.flush();
114 }
115 ++total;
116 if (listener != null) {
117 listener.bytesTransferred(total, 1, streamSize);
118 }
119 continue;
120 }
121
122 dest.write(buffer, 0, bytes);
123 if(flush) {
124 dest.flush();
125 }
126 total += bytes;
127 if (listener != null) {
128 listener.bytesTransferred(total, bytes, streamSize);
129 }
130 }
131 }
132 catch (IOException e)
133 {
134 throw new CopyStreamException("IOException caught while copying.",
135 total, e);
136 }
137
138 return total;
139 }
140
141
142 /***
143 * Copies the contents of an InputStream to an OutputStream using a
144 * copy buffer of a given size and notifies the provided
145 * CopyStreamListener of the progress of the copy operation by calling
146 * its bytesTransferred(long, int) method after each write to the
147 * destination. If you wish to notify more than one listener you should
148 * use a CopyStreamAdapter as the listener and register the additional
149 * listeners with the CopyStreamAdapter.
150 * <p>
151 * The contents of the InputStream are
152 * read until the end of the stream is reached, but neither the
153 * source nor the destination are closed. You must do this yourself
154 * outside of the method call. The number of bytes read/written is
155 * returned.
156 * <p>
157 * @param source The source InputStream.
158 * @param dest The destination OutputStream.
159 * @param bufferSize The number of bytes to buffer during the copy.
160 * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
161 * @param streamSize The number of bytes in the stream being copied.
162 * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
163 * @param listener The CopyStreamListener to notify of progress. If
164 * this parameter is null, notification is not attempted.
165 * @exception CopyStreamException If an error occurs while reading from the
166 * source or writing to the destination. The CopyStreamException
167 * will contain the number of bytes confirmed to have been
168 * transferred before an
169 * IOException occurred, and it will also contain the IOException
170 * that caused the error. These values can be retrieved with
171 * the CopyStreamException getTotalBytesTransferred() and
172 * getIOException() methods.
173 ***/
174 public static final long copyStream(InputStream source, OutputStream dest,
175 int bufferSize, long streamSize,
176 CopyStreamListener listener)
177 throws CopyStreamException
178 {
179 return copyStream(source, dest, bufferSize, streamSize, listener,
180 true);
181 }
182
183
184 /***
185 * Copies the contents of an InputStream to an OutputStream using a
186 * copy buffer of a given size. The contents of the InputStream are
187 * read until the end of the stream is reached, but neither the
188 * source nor the destination are closed. You must do this yourself
189 * outside of the method call. The number of bytes read/written is
190 * returned.
191 * <p>
192 * @param source The source InputStream.
193 * @param dest The destination OutputStream.
194 * @param bufferSize The number of bytes to buffer during the copy.
195 * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
196 * @return The number of bytes read/written in the copy operation.
197 * @exception CopyStreamException If an error occurs while reading from the
198 * source or writing to the destination. The CopyStreamException
199 * will contain the number of bytes confirmed to have been
200 * transferred before an
201 * IOException occurred, and it will also contain the IOException
202 * that caused the error. These values can be retrieved with
203 * the CopyStreamException getTotalBytesTransferred() and
204 * getIOException() methods.
205 ***/
206 public static final long copyStream(InputStream source, OutputStream dest,
207 int bufferSize)
208 throws CopyStreamException
209 {
210 return copyStream(source, dest, bufferSize,
211 CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
212 }
213
214
215 /***
216 * Same as <code> copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
217 ***/
218 public static final long copyStream(InputStream source, OutputStream dest)
219 throws CopyStreamException
220 {
221 return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE);
222 }
223
224
225 /***
226 * Copies the contents of a Reader to a Writer using a
227 * copy buffer of a given size and notifies the provided
228 * CopyStreamListener of the progress of the copy operation by calling
229 * its bytesTransferred(long, int) method after each write to the
230 * destination. If you wish to notify more than one listener you should
231 * use a CopyStreamAdapter as the listener and register the additional
232 * listeners with the CopyStreamAdapter.
233 * <p>
234 * The contents of the Reader are
235 * read until its end is reached, but neither the source nor the
236 * destination are closed. You must do this yourself outside of the
237 * method call. The number of characters read/written is returned.
238 * <p>
239 * @param source The source Reader.
240 * @param dest The destination writer.
241 * @param bufferSize The number of characters to buffer during the copy.
242 * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
243 * @param streamSize The number of characters in the stream being copied.
244 * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
245 * @param listener The CopyStreamListener to notify of progress. If
246 * this parameter is null, notification is not attempted.
247 * @return The number of characters read/written in the copy operation.
248 * @exception CopyStreamException If an error occurs while reading from the
249 * source or writing to the destination. The CopyStreamException
250 * will contain the number of bytes confirmed to have been
251 * transferred before an
252 * IOException occurred, and it will also contain the IOException
253 * that caused the error. These values can be retrieved with
254 * the CopyStreamException getTotalBytesTransferred() and
255 * getIOException() methods.
256 ***/
257 public static final long copyReader(Reader source, Writer dest,
258 int bufferSize, long streamSize,
259 CopyStreamListener listener)
260 throws CopyStreamException
261 {
262 int chars;
263 long total = 0;
264 char[] buffer = new char[bufferSize >= 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE];
265
266 try
267 {
268 while ((chars = source.read(buffer)) != -1)
269 {
270 // Technically, some read(char[]) methods may return 0 and we cannot
271 // accept that as an indication of EOF.
272 if (chars == 0)
273 {
274 chars = source.read();
275 if (chars < 0) {
276 break;
277 }
278 dest.write(chars);
279 dest.flush();
280 ++total;
281 if (listener != null) {
282 listener.bytesTransferred(total, chars, streamSize);
283 }
284 continue;
285 }
286
287 dest.write(buffer, 0, chars);
288 dest.flush();
289 total += chars;
290 if (listener != null) {
291 listener.bytesTransferred(total, chars, streamSize);
292 }
293 }
294 }
295 catch (IOException e)
296 {
297 throw new CopyStreamException("IOException caught while copying.",
298 total, e);
299 }
300
301 return total;
302 }
303
304
305 /***
306 * Copies the contents of a Reader to a Writer using a
307 * copy buffer of a given size. The contents of the Reader are
308 * read until its end is reached, but neither the source nor the
309 * destination are closed. You must do this yourself outside of the
310 * method call. The number of characters read/written is returned.
311 * <p>
312 * @param source The source Reader.
313 * @param dest The destination writer.
314 * @param bufferSize The number of characters to buffer during the copy.
315 * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
316 * @return The number of characters read/written in the copy operation.
317 * @exception CopyStreamException If an error occurs while reading from the
318 * source or writing to the destination. The CopyStreamException
319 * will contain the number of bytes confirmed to have been
320 * transferred before an
321 * IOException occurred, and it will also contain the IOException
322 * that caused the error. These values can be retrieved with
323 * the CopyStreamException getTotalBytesTransferred() and
324 * getIOException() methods.
325 ***/
326 public static final long copyReader(Reader source, Writer dest,
327 int bufferSize)
328 throws CopyStreamException
329 {
330 return copyReader(source, dest, bufferSize,
331 CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
332 }
333
334
335 /***
336 * Same as <code> copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
337 ***/
338 public static final long copyReader(Reader source, Writer dest)
339 throws CopyStreamException
340 {
341 return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE);
342 }
343
344 /**
345 * Closes the object quietly, catching rather than throwing IOException.
346 * Intended for use from finally blocks.
347 *
348 * @param closeable the object to close, may be {@code null}
349 * @since 3.0
350 */
351 public static void closeQuietly(Closeable closeable) {
352 if (closeable != null) {
353 try {
354 closeable.close();
355 } catch (IOException e) {
356 }
357 }
358 }
359
360 /**
361 * Closes the socket quietly, catching rather than throwing IOException.
362 * Intended for use from finally blocks.
363 *
364 * @param socket the socket to close, may be {@code null}
365 * @since 3.0
366 */
367 public static void closeQuietly(Socket socket) {
368 if (socket != null) {
369 try {
370 socket.close();
371 } catch (IOException e) {
372 }
373 }
374 }
375 }