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 }