001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.net.io;
019
020 import java.io.Closeable;
021 import java.io.IOException;
022 import java.io.InputStream;
023 import java.io.OutputStream;
024 import java.io.Reader;
025 import java.io.Writer;
026 import java.net.Socket;
027
028 /***
029 * The Util class cannot be instantiated and stores short static convenience
030 * methods that are often quite useful.
031 * <p>
032 * <p>
033 * @see CopyStreamException
034 * @see CopyStreamListener
035 * @see CopyStreamAdapter
036 ***/
037
038 public final class Util
039 {
040 /***
041 * The default buffer size used by {@link #copyStream copyStream }
042 * and {@link #copyReader copyReader }. It's value is 1024.
043 ***/
044 public static final int DEFAULT_COPY_BUFFER_SIZE = 1024;
045
046 // Cannot be instantiated
047 private Util()
048 { }
049
050
051 /***
052 * Copies the contents of an InputStream to an OutputStream using a
053 * copy buffer of a given size and notifies the provided
054 * CopyStreamListener of the progress of the copy operation by calling
055 * its bytesTransferred(long, int) method after each write to the
056 * destination. If you wish to notify more than one listener you should
057 * use a CopyStreamAdapter as the listener and register the additional
058 * listeners with the CopyStreamAdapter.
059 * <p>
060 * The contents of the InputStream are
061 * read until the end of the stream is reached, but neither the
062 * source nor the destination are closed. You must do this yourself
063 * outside of the method call. The number of bytes read/written is
064 * returned.
065 * <p>
066 * @param source The source InputStream.
067 * @param dest The destination OutputStream.
068 * @param bufferSize The number of bytes to buffer during the copy.
069 * @param streamSize The number of bytes in the stream being copied.
070 * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
071 * @param listener The CopyStreamListener to notify of progress. If
072 * this parameter is null, notification is not attempted.
073 * @param flush Whether to flush the output stream after every
074 * write. This is necessary for interactive sessions that rely on
075 * buffered streams. If you don't flush, the data will stay in
076 * the stream buffer.
077 * @exception CopyStreamException If an error occurs while reading from the
078 * source or writing to the destination. The CopyStreamException
079 * will contain the number of bytes confirmed to have been
080 * transferred before an
081 * IOException occurred, and it will also contain the IOException
082 * that caused the error. These values can be retrieved with
083 * the CopyStreamException getTotalBytesTransferred() and
084 * getIOException() methods.
085 ***/
086 public static final long copyStream(InputStream source, OutputStream dest,
087 int bufferSize, long streamSize,
088 CopyStreamListener listener,
089 boolean flush)
090 throws CopyStreamException
091 {
092 int bytes;
093 long total;
094 byte[] buffer;
095
096 buffer = new byte[bufferSize];
097 total = 0;
098
099 try
100 {
101 while ((bytes = source.read(buffer)) != -1)
102 {
103 // Technically, some read(byte[]) methods may return 0 and we cannot
104 // accept that as an indication of EOF.
105
106 if (bytes == 0)
107 {
108 bytes = source.read();
109 if (bytes < 0) {
110 break;
111 }
112 dest.write(bytes);
113 if(flush) {
114 dest.flush();
115 }
116 ++total;
117 if (listener != null) {
118 listener.bytesTransferred(total, 1, streamSize);
119 }
120 continue;
121 }
122
123 dest.write(buffer, 0, bytes);
124 if(flush) {
125 dest.flush();
126 }
127 total += bytes;
128 if (listener != null) {
129 listener.bytesTransferred(total, bytes, streamSize);
130 }
131 }
132 }
133 catch (IOException e)
134 {
135 throw new CopyStreamException("IOException caught while copying.",
136 total, e);
137 }
138
139 return total;
140 }
141
142
143 /***
144 * Copies the contents of an InputStream to an OutputStream using a
145 * copy buffer of a given size and notifies the provided
146 * CopyStreamListener of the progress of the copy operation by calling
147 * its bytesTransferred(long, int) method after each write to the
148 * destination. If you wish to notify more than one listener you should
149 * use a CopyStreamAdapter as the listener and register the additional
150 * listeners with the CopyStreamAdapter.
151 * <p>
152 * The contents of the InputStream are
153 * read until the end of the stream is reached, but neither the
154 * source nor the destination are closed. You must do this yourself
155 * outside of the method call. The number of bytes read/written is
156 * returned.
157 * <p>
158 * @param source The source InputStream.
159 * @param dest The destination OutputStream.
160 * @param bufferSize The number of bytes to buffer during the copy.
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 * @return The number of bytes read/written in the copy operation.
195 * @exception CopyStreamException If an error occurs while reading from the
196 * source or writing to the destination. The CopyStreamException
197 * will contain the number of bytes confirmed to have been
198 * transferred before an
199 * IOException occurred, and it will also contain the IOException
200 * that caused the error. These values can be retrieved with
201 * the CopyStreamException getTotalBytesTransferred() and
202 * getIOException() methods.
203 ***/
204 public static final long copyStream(InputStream source, OutputStream dest,
205 int bufferSize)
206 throws CopyStreamException
207 {
208 return copyStream(source, dest, bufferSize,
209 CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
210 }
211
212
213 /***
214 * Same as <code> copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
215 ***/
216 public static final long copyStream(InputStream source, OutputStream dest)
217 throws CopyStreamException
218 {
219 return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE);
220 }
221
222
223 /***
224 * Copies the contents of a Reader to a Writer using a
225 * copy buffer of a given size and notifies the provided
226 * CopyStreamListener of the progress of the copy operation by calling
227 * its bytesTransferred(long, int) method after each write to the
228 * destination. If you wish to notify more than one listener you should
229 * use a CopyStreamAdapter as the listener and register the additional
230 * listeners with the CopyStreamAdapter.
231 * <p>
232 * The contents of the Reader are
233 * read until its end is reached, but neither the source nor the
234 * destination are closed. You must do this yourself outside of the
235 * method call. The number of characters read/written is returned.
236 * <p>
237 * @param source The source Reader.
238 * @param dest The destination writer.
239 * @param bufferSize The number of characters to buffer during the copy.
240 * @param streamSize The number of characters in the stream being copied.
241 * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
242 * @param listener The CopyStreamListener to notify of progress. If
243 * this parameter is null, notification is not attempted.
244 * @return The number of characters read/written in the copy operation.
245 * @exception CopyStreamException If an error occurs while reading from the
246 * source or writing to the destination. The CopyStreamException
247 * will contain the number of bytes confirmed to have been
248 * transferred before an
249 * IOException occurred, and it will also contain the IOException
250 * that caused the error. These values can be retrieved with
251 * the CopyStreamException getTotalBytesTransferred() and
252 * getIOException() methods.
253 ***/
254 public static final long copyReader(Reader source, Writer dest,
255 int bufferSize, long streamSize,
256 CopyStreamListener listener)
257 throws CopyStreamException
258 {
259 int chars;
260 long total;
261 char[] buffer;
262
263 buffer = new char[bufferSize];
264 total = 0;
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 * @return The number of characters read/written in the copy operation.
316 * @exception CopyStreamException If an error occurs while reading from the
317 * source or writing to the destination. The CopyStreamException
318 * will contain the number of bytes confirmed to have been
319 * transferred before an
320 * IOException occurred, and it will also contain the IOException
321 * that caused the error. These values can be retrieved with
322 * the CopyStreamException getTotalBytesTransferred() and
323 * getIOException() methods.
324 ***/
325 public static final long copyReader(Reader source, Writer dest,
326 int bufferSize)
327 throws CopyStreamException
328 {
329 return copyReader(source, dest, bufferSize,
330 CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
331 }
332
333
334 /***
335 * Same as <code> copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
336 ***/
337 public static final long copyReader(Reader source, Writer dest)
338 throws CopyStreamException
339 {
340 return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE);
341 }
342
343 /**
344 * Closes the object quietly, catching rather than throwing IOException.
345 * Intended for use from finally blocks.
346 *
347 * @param closeable the object to close, may be {@code null}
348 * @since 3.0
349 */
350 public static void closeQuietly(Closeable closeable) {
351 if (closeable != null) {
352 try {
353 closeable.close();
354 } catch (IOException e) {
355 }
356 }
357 }
358
359 /**
360 * Closes the socket quietly, catching rather than throwing IOException.
361 * Intended for use from finally blocks.
362 *
363 * @param socket the socket to close, may be {@code null}
364 * @since 3.0
365 */
366 public static void closeQuietly(Socket socket) {
367 if (socket != null) {
368 try {
369 socket.close();
370 } catch (IOException e) {
371 }
372 }
373 }
374 }