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 * https://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.OutputStreamWriter; 025import java.io.PrintStream; 026import java.io.PrintWriter; 027import java.io.Reader; 028import java.io.Writer; 029import java.net.Socket; 030import java.nio.charset.Charset; 031import java.util.concurrent.atomic.AtomicLong; 032 033import org.apache.commons.io.IOUtils; 034import org.apache.commons.io.output.ProxyOutputStream; 035import org.apache.commons.io.output.ProxyWriter; 036 037/** 038 * The Util class cannot be instantiated and stores short static convenience methods that are often quite useful. 039 * 040 * @see CopyStreamException 041 * @see CopyStreamListener 042 * @see CopyStreamAdapter 043 */ 044public final class Util { 045 046 /** 047 * The default buffer size ({@value}) used by {@link #copyStream copyStream} and {@link #copyReader copyReader} and by the copyReader/copyStream methods if 048 * a zero or negative buffer size is supplied. 049 */ 050 public static final int DEFAULT_COPY_BUFFER_SIZE = IOUtils.DEFAULT_BUFFER_SIZE; 051 052 /** 053 * Closes the object quietly, catching rather than throwing IOException. Intended for use from finally blocks. 054 * 055 * @param closeable the object to close, may be {@code null} 056 * @since 3.0 057 * @deprecated Use {@link IOUtils#closeQuietly(Closeable)}. 058 */ 059 @Deprecated 060 public static void closeQuietly(final Closeable closeable) { 061 IOUtils.closeQuietly(closeable); 062 } 063 064 /** 065 * Closes the socket quietly, catching rather than throwing IOException. Intended for use from finally blocks. 066 * 067 * @param socket the socket to close, may be {@code null} 068 * @since 3.0 069 * @deprecated Use {@link IOUtils#closeQuietly(Socket)}. 070 */ 071 @Deprecated 072 public static void closeQuietly(final Socket socket) { 073 IOUtils.closeQuietly(socket); 074 } 075 076 /** 077 * Same as {@code copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE);} 078 * 079 * @param source where to copy from 080 * @param dest where to copy to 081 * @return number of bytes copied 082 * @throws CopyStreamException on error 083 * @deprecated Use {@link IOUtils#copy(Reader, Writer)}. 084 */ 085 @Deprecated 086 public static long copyReader(final Reader source, final Writer dest) throws CopyStreamException { 087 return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); 088 } 089 090 /** 091 * Copies the contents of a Reader to a Writer using a copy buffer of a given size. The contents of the Reader are read until its end is reached, but 092 * neither the source nor the destination are closed. You must do this yourself outside the method call. The number of characters read/written is 093 * returned. 094 * 095 * @param source The source Reader. 096 * @param dest The destination writer. 097 * @param bufferSize The number of characters to buffer during the copy. A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. 098 * @return The number of characters read/written in the copy operation. 099 * @throws CopyStreamException If an error occurs while reading from the source or writing to the destination. The CopyStreamException will contain the 100 * number of bytes confirmed to have been transferred before an IOException occurred, and it will also contain the IOException 101 * that caused the error. These values can be retrieved with the CopyStreamException getTotalBytesTransferred() and 102 * getIOException() methods. 103 */ 104 public static long copyReader(final Reader source, final Writer dest, final int bufferSize) throws CopyStreamException { 105 return copyReader(source, dest, bufferSize, CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); 106 } 107 108 /** 109 * Copies the contents of a Reader to a Writer using a copy buffer of a given size and notifies the provided CopyStreamListener of the progress of the copy 110 * operation by calling its bytesTransferred(long, int) method after each write to the destination. If you wish to notify more than one listener you should 111 * use a CopyStreamAdapter as the listener and register the additional listeners with the CopyStreamAdapter. 112 * <p> 113 * The contents of the Reader are read until its end is reached, but neither the source nor the destination are closed. You must do this yourself outside 114 * the method call. The number of characters read/written is returned. 115 * </p> 116 * 117 * @param source The source Reader. 118 * @param dest The destination writer. 119 * @param bufferSize The number of characters to buffer during the copy. A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. 120 * @param streamSize The number of characters in the stream being copied. Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. Not currently 121 * used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)} 122 * @param listener The CopyStreamListener to notify of progress. If this parameter is null, notification is not attempted. 123 * @return The number of characters read/written in the copy operation. 124 * @throws CopyStreamException If an error occurs while reading from the source or writing to the destination. The CopyStreamException will contain the 125 * number of bytes confirmed to have been transferred before an IOException occurred, and it will also contain the IOException 126 * that caused the error. These values can be retrieved with the CopyStreamException getTotalBytesTransferred() and 127 * getIOException() methods. 128 */ 129 public static long copyReader(final Reader source, final Writer dest, final int bufferSize, final long streamSize, final CopyStreamListener listener) 130 throws CopyStreamException { 131 final AtomicLong total = new AtomicLong(); 132 try { 133 return IOUtils.copyLarge(source, listener == null ? dest : new ProxyWriter(dest) { 134 135 @Override 136 protected void afterWrite(int n) throws IOException { 137 dest.flush(); 138 listener.bytesTransferred(total.addAndGet(n), n, streamSize); 139 } 140 }, new char[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]); 141 } catch (IOException e) { 142 throw new CopyStreamException("IOException caught while copying.", total.get(), e); 143 } 144 } 145 146 /** 147 * Same as {@code copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE);} 148 * 149 * @param source where to copy from 150 * @param dest where to copy to 151 * @return number of bytes copied 152 * @throws CopyStreamException on error 153 */ 154 public static long copyStream(final InputStream source, final OutputStream dest) throws CopyStreamException { 155 return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); 156 } 157 158 /** 159 * Copies the contents of an InputStream to an OutputStream using a copy buffer of a given size. The contents of the InputStream are read until the end of 160 * the stream is reached, but neither the source nor the destination are closed. You must do this yourself outside the method call. The number of bytes 161 * read/written is returned. 162 * 163 * @param source The source InputStream. 164 * @param dest The destination OutputStream. 165 * @param bufferSize The number of bytes to buffer during the copy. A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. 166 * @return The number of bytes read/written in the copy operation. 167 * @throws CopyStreamException If an error occurs while reading from the source or writing to the destination. The CopyStreamException will contain the 168 * number of bytes confirmed to have been transferred before an IOException occurred, and it will also contain the IOException 169 * that caused the error. These values can be retrieved with the CopyStreamException getTotalBytesTransferred() and 170 * getIOException() methods. 171 */ 172 public static long copyStream(final InputStream source, final OutputStream dest, final int bufferSize) throws CopyStreamException { 173 return copyStream(source, dest, bufferSize, CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); 174 } 175 176 /** 177 * Copies the contents of an InputStream to an OutputStream using a copy buffer of a given size and notifies the provided CopyStreamListener of the progress 178 * of the copy operation by calling its bytesTransferred(long, int) method after each write to the destination. If you wish to notify more than one listener 179 * you should use a CopyStreamAdapter as the listener and register the additional listeners with the CopyStreamAdapter. 180 * <p> 181 * The contents of the InputStream are read until the end of the stream is reached, but neither the source nor the destination are closed. You must do this 182 * yourself outside the method call. The number of bytes read/written is returned. 183 * 184 * @param source The source InputStream. 185 * @param dest The destination OutputStream. 186 * @param bufferSize The number of bytes to buffer during the copy. A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. 187 * @param streamSize The number of bytes in the stream being copied. Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. Not currently used 188 * (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)} 189 * @param listener The CopyStreamListener to notify of progress. If this parameter is null, notification is not attempted. 190 * @return number of bytes read/written 191 * @throws CopyStreamException If an error occurs while reading from the source or writing to the destination. The CopyStreamException will contain the 192 * number of bytes confirmed to have been transferred before an IOException occurred, and it will also contain the IOException 193 * that caused the error. These values can be retrieved with the CopyStreamException getTotalBytesTransferred() and 194 * getIOException() methods. 195 */ 196 public static long copyStream(final InputStream source, final OutputStream dest, final int bufferSize, final long streamSize, 197 final CopyStreamListener listener) throws CopyStreamException { 198 return copyStream(source, dest, bufferSize, streamSize, listener, true); 199 } 200 201 /** 202 * Copies the contents of an InputStream to an OutputStream using a copy buffer of a given size and notifies the provided CopyStreamListener of the progress 203 * of the copy operation by calling its bytesTransferred(long, int) method after each write to the destination. If you wish to notify more than one listener 204 * you should use a CopyStreamAdapter as the listener and register the additional listeners with the CopyStreamAdapter. 205 * <p> 206 * The contents of the InputStream are read until the end of the stream is reached, but neither the source nor the destination are closed. You must do this 207 * yourself outside the method call. The number of bytes read/written is returned. 208 * 209 * @param source The source InputStream. 210 * @param dest The destination OutputStream. 211 * @param bufferSize The number of bytes to buffer during the copy. A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. 212 * @param streamSize The number of bytes in the stream being copied. Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. Not currently used 213 * (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)} 214 * @param listener The CopyStreamListener to notify of progress. If this parameter is null, notification is not attempted. 215 * @param flush Whether to flush the output stream after every write. This is necessary for interactive sessions that rely on buffered streams. If you 216 * don't flush, the data will stay in the stream buffer. 217 * @return number of bytes read/written 218 * @throws CopyStreamException If an error occurs while reading from the source or writing to the destination. The CopyStreamException will contain the 219 * number of bytes confirmed to have been transferred before an IOException occurred, and it will also contain the IOException 220 * that caused the error. These values can be retrieved with the CopyStreamException getTotalBytesTransferred() and 221 * getIOException() methods. 222 */ 223 public static long copyStream(final InputStream source, final OutputStream dest, final int bufferSize, final long streamSize, 224 final CopyStreamListener listener, final boolean flush) throws CopyStreamException { 225 final AtomicLong total = new AtomicLong(); 226 try { 227 return IOUtils.copyLarge(source, listener == null ? dest : new ProxyOutputStream(dest) { 228 229 @Override 230 protected void afterWrite(int n) throws IOException { 231 if (flush) { 232 dest.flush(); 233 } 234 listener.bytesTransferred(total.addAndGet(n), n, streamSize); 235 } 236 237 }, new byte[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]); 238 } catch (IOException e) { 239 throw new CopyStreamException("IOException caught while copying.", total.get(), e); 240 } 241 } 242 243 /** 244 * Creates a new PrintWriter using the default encoding. 245 * 246 * @param printStream the target PrintStream. 247 * @return a new PrintWriter. 248 * @since 3.11.0 249 */ 250 public static PrintWriter newPrintWriter(final PrintStream printStream) { 251 return new PrintWriter(new OutputStreamWriter(printStream, Charset.defaultCharset())); 252 } 253 254 /** Cannot be instantiated. */ 255 private Util() { 256 } 257}