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 dest.write(bytes);
112 if(flush)
113 dest.flush();
114 ++total;
115 if (listener != null)
116 listener.bytesTransferred(total, 1, streamSize);
117 continue;
118 }
119
120 dest.write(buffer, 0, bytes);
121 if(flush)
122 dest.flush();
123 total += bytes;
124 if (listener != null)
125 listener.bytesTransferred(total, bytes, streamSize);
126 }
127 }
128 catch (IOException e)
129 {
130 throw new CopyStreamException("IOException caught while copying.",
131 total, e);
132 }
133
134 return total;
135 }
136
137
138 /***
139 * Copies the contents of an InputStream to an OutputStream using a
140 * copy buffer of a given size and notifies the provided
141 * CopyStreamListener of the progress of the copy operation by calling
142 * its bytesTransferred(long, int) method after each write to the
143 * destination. If you wish to notify more than one listener you should
144 * use a CopyStreamAdapter as the listener and register the additional
145 * listeners with the CopyStreamAdapter.
146 * <p>
147 * The contents of the InputStream are
148 * read until the end of the stream is reached, but neither the
149 * source nor the destination are closed. You must do this yourself
150 * outside of the method call. The number of bytes read/written is
151 * returned.
152 * <p>
153 * @param source The source InputStream.
154 * @param dest The destination OutputStream.
155 * @param bufferSize The number of bytes to buffer during the copy.
156 * @param streamSize The number of bytes in the stream being copied.
157 * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
158 * @param listener The CopyStreamListener to notify of progress. If
159 * this parameter is null, notification is not attempted.
160 * @exception CopyStreamException If an error occurs while reading from the
161 * source or writing to the destination. The CopyStreamException
162 * will contain the number of bytes confirmed to have been
163 * transferred before an
164 * IOException occurred, and it will also contain the IOException
165 * that caused the error. These values can be retrieved with
166 * the CopyStreamException getTotalBytesTransferred() and
167 * getIOException() methods.
168 ***/
169 public static final long copyStream(InputStream source, OutputStream dest,
170 int bufferSize, long streamSize,
171 CopyStreamListener listener)
172 throws CopyStreamException
173 {
174 return copyStream(source, dest, bufferSize, streamSize, listener,
175 true);
176 }
177
178
179 /***
180 * Copies the contents of an InputStream to an OutputStream using a
181 * copy buffer of a given size. The contents of the InputStream are
182 * read until the end of the stream is reached, but neither the
183 * source nor the destination are closed. You must do this yourself
184 * outside of the method call. The number of bytes read/written is
185 * returned.
186 * <p>
187 * @param source The source InputStream.
188 * @param dest The destination OutputStream.
189 * @return The number of bytes read/written in the copy operation.
190 * @exception CopyStreamException If an error occurs while reading from the
191 * source or writing to the destination. The CopyStreamException
192 * will contain the number of bytes confirmed to have been
193 * transferred before an
194 * IOException occurred, and it will also contain the IOException
195 * that caused the error. These values can be retrieved with
196 * the CopyStreamException getTotalBytesTransferred() and
197 * getIOException() methods.
198 ***/
199 public static final long copyStream(InputStream source, OutputStream dest,
200 int bufferSize)
201 throws CopyStreamException
202 {
203 return copyStream(source, dest, bufferSize,
204 CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
205 }
206
207
208 /***
209 * Same as <code> copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
210 ***/
211 public static final long copyStream(InputStream source, OutputStream dest)
212 throws CopyStreamException
213 {
214 return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE);
215 }
216
217
218 /***
219 * Copies the contents of a Reader to a Writer using a
220 * copy buffer of a given size and notifies the provided
221 * CopyStreamListener of the progress of the copy operation by calling
222 * its bytesTransferred(long, int) method after each write to the
223 * destination. If you wish to notify more than one listener you should
224 * use a CopyStreamAdapter as the listener and register the additional
225 * listeners with the CopyStreamAdapter.
226 * <p>
227 * The contents of the Reader are
228 * read until its end is reached, but neither the source nor the
229 * destination are closed. You must do this yourself outside of the
230 * method call. The number of characters read/written is returned.
231 * <p>
232 * @param source The source Reader.
233 * @param dest The destination writer.
234 * @param bufferSize The number of characters to buffer during the copy.
235 * @param streamSize The number of characters in the stream being copied.
236 * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
237 * @param listener The CopyStreamListener to notify of progress. If
238 * this parameter is null, notification is not attempted.
239 * @return The number of characters read/written in the copy operation.
240 * @exception CopyStreamException If an error occurs while reading from the
241 * source or writing to the destination. The CopyStreamException
242 * will contain the number of bytes confirmed to have been
243 * transferred before an
244 * IOException occurred, and it will also contain the IOException
245 * that caused the error. These values can be retrieved with
246 * the CopyStreamException getTotalBytesTransferred() and
247 * getIOException() methods.
248 ***/
249 public static final long copyReader(Reader source, Writer dest,
250 int bufferSize, long streamSize,
251 CopyStreamListener listener)
252 throws CopyStreamException
253 {
254 int chars;
255 long total;
256 char[] buffer;
257
258 buffer = new char[bufferSize];
259 total = 0;
260
261 try
262 {
263 while ((chars = source.read(buffer)) != -1)
264 {
265 // Technically, some read(char[]) methods may return 0 and we cannot
266 // accept that as an indication of EOF.
267 if (chars == 0)
268 {
269 chars = source.read();
270 if (chars < 0)
271 break;
272 dest.write(chars);
273 dest.flush();
274 ++total;
275 if (listener != null)
276 listener.bytesTransferred(total, chars, streamSize);
277 continue;
278 }
279
280 dest.write(buffer, 0, chars);
281 dest.flush();
282 total += chars;
283 if (listener != null)
284 listener.bytesTransferred(total, chars, streamSize);
285 }
286 }
287 catch (IOException e)
288 {
289 throw new CopyStreamException("IOException caught while copying.",
290 total, e);
291 }
292
293 return total;
294 }
295
296
297 /***
298 * Copies the contents of a Reader to a Writer using a
299 * copy buffer of a given size. The contents of the Reader are
300 * read until its end is reached, but neither the source nor the
301 * destination are closed. You must do this yourself outside of the
302 * method call. The number of characters read/written is returned.
303 * <p>
304 * @param source The source Reader.
305 * @param dest The destination writer.
306 * @param bufferSize The number of characters to buffer during the copy.
307 * @return The number of characters read/written in the copy operation.
308 * @exception CopyStreamException If an error occurs while reading from the
309 * source or writing to the destination. The CopyStreamException
310 * will contain the number of bytes confirmed to have been
311 * transferred before an
312 * IOException occurred, and it will also contain the IOException
313 * that caused the error. These values can be retrieved with
314 * the CopyStreamException getTotalBytesTransferred() and
315 * getIOException() methods.
316 ***/
317 public static final long copyReader(Reader source, Writer dest,
318 int bufferSize)
319 throws CopyStreamException
320 {
321 return copyReader(source, dest, bufferSize,
322 CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
323 }
324
325
326 /***
327 * Same as <code> copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
328 ***/
329 public static final long copyReader(Reader source, Writer dest)
330 throws CopyStreamException
331 {
332 return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE);
333 }
334
335 /**
336 * Closes the object quietly, catching rather than throwing IOException.
337 * Intended for use from finally blocks.
338 *
339 * @param closeable the object to close, may be {@code null}
340 * @since 3.0
341 */
342 public static void closeQuietly(Closeable closeable) {
343 if (closeable != null) {
344 try {
345 closeable.close();
346 } catch (IOException e) {
347 }
348 }
349 }
350
351 /**
352 * Closes the socket quietly, catching rather than throwing IOException.
353 * Intended for use from finally blocks.
354 *
355 * @param socket the socket to close, may be {@code null}
356 * @since 3.0
357 */
358 public static void closeQuietly(Socket socket) {
359 if (socket != null) {
360 try {
361 socket.close();
362 } catch (IOException e) {
363 }
364 }
365 }
366 }