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 018package org.apache.commons.net.io; 019 020import java.io.Closeable; 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.OutputStream; 024import java.io.Reader; 025import java.io.Writer; 026import 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 038public final class Util 039{ 040 /** 041 * The default buffer size ({@value}) used by 042 * {@link #copyStream copyStream } and {@link #copyReader copyReader} 043 * and by the copyReader/copyStream methods if a zero or negative buffer size is supplied. 044 */ 045 public static final int DEFAULT_COPY_BUFFER_SIZE = 1024; 046 047 // Cannot be instantiated 048 private Util() 049 { } 050 051 052 /*** 053 * Copies the contents of an InputStream to an OutputStream using a 054 * copy buffer of a given size and notifies the provided 055 * CopyStreamListener of the progress of the copy operation by calling 056 * its bytesTransferred(long, int) method after each write to the 057 * destination. If you wish to notify more than one listener you should 058 * use a CopyStreamAdapter as the listener and register the additional 059 * listeners with the CopyStreamAdapter. 060 * <p> 061 * The contents of the InputStream are 062 * read until the end of the stream is reached, but neither the 063 * source nor the destination are closed. You must do this yourself 064 * outside of the method call. The number of bytes read/written is 065 * returned. 066 * <p> 067 * @param source The source InputStream. 068 * @param dest The destination OutputStream. 069 * @param bufferSize The number of bytes to buffer during the copy. 070 * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. 071 * @param streamSize The number of bytes in the stream being copied. 072 * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. 073 * @param listener The CopyStreamListener to notify of progress. If 074 * this parameter is null, notification is not attempted. 075 * @param flush Whether to flush the output stream after every 076 * write. This is necessary for interactive sessions that rely on 077 * buffered streams. If you don't flush, the data will stay in 078 * the stream buffer. 079 * @exception CopyStreamException If an error occurs while reading from the 080 * source or writing to the destination. The CopyStreamException 081 * will contain the number of bytes confirmed to have been 082 * transferred before an 083 * IOException occurred, and it will also contain the IOException 084 * that caused the error. These values can be retrieved with 085 * the CopyStreamException getTotalBytesTransferred() and 086 * getIOException() methods. 087 ***/ 088 public static final long copyStream(InputStream source, OutputStream dest, 089 int bufferSize, long streamSize, 090 CopyStreamListener listener, 091 boolean flush) 092 throws CopyStreamException 093 { 094 int bytes; 095 long total = 0; 096 byte[] buffer = new byte[bufferSize >= 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]; 097 098 try 099 { 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}