001 /*
002 * Copyright 2001-2005 The Apache Software Foundation
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.apache.commons.net.io;
017
018 import java.io.IOException;
019 import java.io.InputStream;
020 import java.io.OutputStream;
021 import java.io.Reader;
022 import java.io.Writer;
023
024 /***
025 * The Util class cannot be instantiated and stores short static convenience
026 * methods that are often quite useful.
027 * <p>
028 * <p>
029 * @see CopyStreamException
030 * @see CopyStreamListener
031 * @see CopyStreamAdapter
032 * @author Daniel F. Savarese
033 ***/
034
035 public final class Util
036 {
037 /***
038 * The default buffer size used by {@link #copyStream copyStream }
039 * and {@link #copyReader copyReader }. It's value is 1024.
040 ***/
041 public static final int DEFAULT_COPY_BUFFER_SIZE = 1024;
042
043 // Cannot be instantiated
044 private Util()
045 { }
046
047
048 /***
049 * Copies the contents of an InputStream to an OutputStream using a
050 * copy buffer of a given size and notifies the provided
051 * CopyStreamListener of the progress of the copy operation by calling
052 * its bytesTransferred(long, int) method after each write to the
053 * destination. If you wish to notify more than one listener you should
054 * use a CopyStreamAdapter as the listener and register the additional
055 * listeners with the CopyStreamAdapter.
056 * <p>
057 * The contents of the InputStream are
058 * read until the end of the stream is reached, but neither the
059 * source nor the destination are closed. You must do this yourself
060 * outside of the method call. The number of bytes read/written is
061 * returned.
062 * <p>
063 * @param source The source InputStream.
064 * @param dest The destination OutputStream.
065 * @param bufferSize The number of bytes to buffer during the copy.
066 * @param streamSize The number of bytes in the stream being copied.
067 * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
068 * @param listener The CopyStreamListener to notify of progress. If
069 * this parameter is null, notification is not attempted.
070 * @param flush Whether to flush the output stream after every
071 * write. This is necessary for interactive sessions that rely on
072 * buffered streams. If you don't flush, the data will stay in
073 * the stream buffer.
074 * @exception CopyStreamException If an error occurs while reading from the
075 * source or writing to the destination. The CopyStreamException
076 * will contain the number of bytes confirmed to have been
077 * transferred before an
078 * IOException occurred, and it will also contain the IOException
079 * that caused the error. These values can be retrieved with
080 * the CopyStreamException getTotalBytesTransferred() and
081 * getIOException() methods.
082 ***/
083 public static final long copyStream(InputStream source, OutputStream dest,
084 int bufferSize, long streamSize,
085 CopyStreamListener listener,
086 boolean flush)
087 throws CopyStreamException
088 {
089 int bytes;
090 long total;
091 byte[] buffer;
092
093 buffer = new byte[bufferSize];
094 total = 0;
095
096 try
097 {
098 while ((bytes = source.read(buffer)) != -1)
099 {
100 // Technically, some read(byte[]) methods may return 0 and we cannot
101 // accept that as an indication of EOF.
102
103 if (bytes == 0)
104 {
105 bytes = source.read();
106 if (bytes < 0)
107 break;
108 dest.write(bytes);
109 if(flush)
110 dest.flush();
111 ++total;
112 if (listener != null)
113 listener.bytesTransferred(total, 1, streamSize);
114 continue;
115 }
116
117 dest.write(buffer, 0, bytes);
118 if(flush)
119 dest.flush();
120 total += bytes;
121 if (listener != null)
122 listener.bytesTransferred(total, bytes, streamSize);
123 }
124 }
125 catch (IOException e)
126 {
127 throw new CopyStreamException("IOException caught while copying.",
128 total, e);
129 }
130
131 return total;
132 }
133
134
135 /***
136 * Copies the contents of an InputStream to an OutputStream using a
137 * copy buffer of a given size and notifies the provided
138 * CopyStreamListener of the progress of the copy operation by calling
139 * its bytesTransferred(long, int) method after each write to the
140 * destination. If you wish to notify more than one listener you should
141 * use a CopyStreamAdapter as the listener and register the additional
142 * listeners with the CopyStreamAdapter.
143 * <p>
144 * The contents of the InputStream are
145 * read until the end of the stream is reached, but neither the
146 * source nor the destination are closed. You must do this yourself
147 * outside of the method call. The number of bytes read/written is
148 * returned.
149 * <p>
150 * @param source The source InputStream.
151 * @param dest The destination OutputStream.
152 * @param bufferSize The number of bytes to buffer during the copy.
153 * @param streamSize The number of bytes in the stream being copied.
154 * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
155 * @param listener The CopyStreamListener to notify of progress. If
156 * this parameter is null, notification is not attempted.
157 * @exception CopyStreamException If an error occurs while reading from the
158 * source or writing to the destination. The CopyStreamException
159 * will contain the number of bytes confirmed to have been
160 * transferred before an
161 * IOException occurred, and it will also contain the IOException
162 * that caused the error. These values can be retrieved with
163 * the CopyStreamException getTotalBytesTransferred() and
164 * getIOException() methods.
165 ***/
166 public static final long copyStream(InputStream source, OutputStream dest,
167 int bufferSize, long streamSize,
168 CopyStreamListener listener)
169 throws CopyStreamException
170 {
171 return copyStream(source, dest, bufferSize, streamSize, listener,
172 true);
173 }
174
175
176 /***
177 * Copies the contents of an InputStream to an OutputStream using a
178 * copy buffer of a given size. The contents of the InputStream are
179 * read until the end of the stream is reached, but neither the
180 * source nor the destination are closed. You must do this yourself
181 * outside of the method call. The number of bytes read/written is
182 * returned.
183 * <p>
184 * @param source The source InputStream.
185 * @param dest The destination OutputStream.
186 * @return The number of bytes read/written in the copy operation.
187 * @exception CopyStreamException If an error occurs while reading from the
188 * source or writing to the destination. The CopyStreamException
189 * will contain the number of bytes confirmed to have been
190 * transferred before an
191 * IOException occurred, and it will also contain the IOException
192 * that caused the error. These values can be retrieved with
193 * the CopyStreamException getTotalBytesTransferred() and
194 * getIOException() methods.
195 ***/
196 public static final long copyStream(InputStream source, OutputStream dest,
197 int bufferSize)
198 throws CopyStreamException
199 {
200 return copyStream(source, dest, bufferSize,
201 CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
202 }
203
204
205 /***
206 * Same as <code> copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
207 ***/
208 public static final long copyStream(InputStream source, OutputStream dest)
209 throws CopyStreamException
210 {
211 return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE);
212 }
213
214
215 /***
216 * Copies the contents of a Reader to a Writer using a
217 * copy buffer of a given size and notifies the provided
218 * CopyStreamListener of the progress of the copy operation by calling
219 * its bytesTransferred(long, int) method after each write to the
220 * destination. If you wish to notify more than one listener you should
221 * use a CopyStreamAdapter as the listener and register the additional
222 * listeners with the CopyStreamAdapter.
223 * <p>
224 * The contents of the Reader are
225 * read until its end is reached, but neither the source nor the
226 * destination are closed. You must do this yourself outside of the
227 * method call. The number of characters read/written is returned.
228 * <p>
229 * @param source The source Reader.
230 * @param dest The destination writer.
231 * @param bufferSize The number of characters to buffer during the copy.
232 * @param streamSize The number of characters in the stream being copied.
233 * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
234 * @param listener The CopyStreamListener to notify of progress. If
235 * this parameter is null, notification is not attempted.
236 * @return The number of characters read/written in the copy operation.
237 * @exception CopyStreamException If an error occurs while reading from the
238 * source or writing to the destination. The CopyStreamException
239 * will contain the number of bytes confirmed to have been
240 * transferred before an
241 * IOException occurred, and it will also contain the IOException
242 * that caused the error. These values can be retrieved with
243 * the CopyStreamException getTotalBytesTransferred() and
244 * getIOException() methods.
245 ***/
246 public static final long copyReader(Reader source, Writer dest,
247 int bufferSize, long streamSize,
248 CopyStreamListener listener)
249 throws CopyStreamException
250 {
251 int chars;
252 long total;
253 char[] buffer;
254
255 buffer = new char[bufferSize];
256 total = 0;
257
258 try
259 {
260 while ((chars = source.read(buffer)) != -1)
261 {
262 // Technically, some read(char[]) methods may return 0 and we cannot
263 // accept that as an indication of EOF.
264 if (chars == 0)
265 {
266 chars = source.read();
267 if (chars < 0)
268 break;
269 dest.write(chars);
270 dest.flush();
271 ++total;
272 if (listener != null)
273 listener.bytesTransferred(total, chars, streamSize);
274 continue;
275 }
276
277 dest.write(buffer, 0, chars);
278 dest.flush();
279 total += chars;
280 if (listener != null)
281 listener.bytesTransferred(total, chars, streamSize);
282 }
283 }
284 catch (IOException e)
285 {
286 throw new CopyStreamException("IOException caught while copying.",
287 total, e);
288 }
289
290 return total;
291 }
292
293
294 /***
295 * Copies the contents of a Reader to a Writer using a
296 * copy buffer of a given size. The contents of the Reader are
297 * read until its end is reached, but neither the source nor the
298 * destination are closed. You must do this yourself outside of the
299 * method call. The number of characters read/written is returned.
300 * <p>
301 * @param source The source Reader.
302 * @param dest The destination writer.
303 * @param bufferSize The number of characters to buffer during the copy.
304 * @return The number of characters read/written in the copy operation.
305 * @exception CopyStreamException If an error occurs while reading from the
306 * source or writing to the destination. The CopyStreamException
307 * will contain the number of bytes confirmed to have been
308 * transferred before an
309 * IOException occurred, and it will also contain the IOException
310 * that caused the error. These values can be retrieved with
311 * the CopyStreamException getTotalBytesTransferred() and
312 * getIOException() methods.
313 ***/
314 public static final long copyReader(Reader source, Writer dest,
315 int bufferSize)
316 throws CopyStreamException
317 {
318 return copyReader(source, dest, bufferSize,
319 CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
320 }
321
322
323 /***
324 * Same as <code> copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
325 ***/
326 public static final long copyReader(Reader source, Writer dest)
327 throws CopyStreamException
328 {
329 return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE);
330 }
331
332 }