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 }