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 }