View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.net.io;
19  
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.OutputStream;
23  import java.io.Reader;
24  import java.io.Writer;
25  
26  /***
27   * The Util class cannot be instantiated and stores short static convenience
28   * methods that are often quite useful.
29   * <p>
30   * <p>
31   * @see CopyStreamException
32   * @see CopyStreamListener
33   * @see CopyStreamAdapter
34   * @author Daniel F. Savarese
35   ***/
36  
37  public final class Util
38  {
39      /***
40       * The default buffer size used by {@link #copyStream  copyStream }
41       * and {@link #copyReader  copyReader }. It's value is 1024.
42       ***/
43      public static final int DEFAULT_COPY_BUFFER_SIZE = 1024;
44  
45      // Cannot be instantiated
46      private Util()
47      { }
48  
49  
50      /***
51       * Copies the contents of an InputStream to an OutputStream using a
52       * copy buffer of a given size and notifies the provided
53       * CopyStreamListener of the progress of the copy operation by calling
54       * its bytesTransferred(long, int) method after each write to the
55       * destination.  If you wish to notify more than one listener you should
56       * use a CopyStreamAdapter as the listener and register the additional
57       * listeners with the CopyStreamAdapter.
58       * <p>
59       * The contents of the InputStream are
60       * read until the end of the stream is reached, but neither the
61       * source nor the destination are closed.  You must do this yourself
62       * outside of the method call.  The number of bytes read/written is
63       * returned.
64       * <p>
65       * @param source  The source InputStream.
66       * @param dest    The destination OutputStream.
67       * @param bufferSize  The number of bytes to buffer during the copy.
68       * @param streamSize  The number of bytes in the stream being copied.
69       *          Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
70       * @param listener  The CopyStreamListener to notify of progress.  If
71       *      this parameter is null, notification is not attempted.
72       * @param flush Whether to flush the output stream after every
73       *        write.  This is necessary for interactive sessions that rely on
74       *        buffered streams.  If you don't flush, the data will stay in
75       *        the stream buffer.
76       * @exception CopyStreamException  If an error occurs while reading from the
77       *            source or writing to the destination.  The CopyStreamException
78       *            will contain the number of bytes confirmed to have been
79       *            transferred before an
80       *            IOException occurred, and it will also contain the IOException
81       *            that caused the error.  These values can be retrieved with
82       *            the CopyStreamException getTotalBytesTransferred() and
83       *            getIOException() methods.
84       ***/
85      public static final long copyStream(InputStream source, OutputStream dest,
86                                          int bufferSize, long streamSize,
87                                          CopyStreamListener listener,
88                                          boolean flush)
89      throws CopyStreamException
90      {
91          int bytes;
92          long total;
93          byte[] buffer;
94  
95          buffer = new byte[bufferSize];
96          total = 0;
97  
98          try
99          {
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                     dest.write(bytes);
111                     if(flush)
112                       dest.flush();
113                     ++total;
114                     if (listener != null)
115                         listener.bytesTransferred(total, 1, streamSize);
116                     continue;
117                 }
118 
119                 dest.write(buffer, 0, bytes);
120                 if(flush)
121                   dest.flush();
122                 total += bytes;
123                 if (listener != null)
124                     listener.bytesTransferred(total, bytes, streamSize);
125             }
126         }
127         catch (IOException e)
128         {
129             throw new CopyStreamException("IOException caught while copying.",
130                                           total, e);
131         }
132 
133         return total;
134     }
135 
136 
137     /***
138      * Copies the contents of an InputStream to an OutputStream using a
139      * copy buffer of a given size and notifies the provided
140      * CopyStreamListener of the progress of the copy operation by calling
141      * its bytesTransferred(long, int) method after each write to the
142      * destination.  If you wish to notify more than one listener you should
143      * use a CopyStreamAdapter as the listener and register the additional
144      * listeners with the CopyStreamAdapter.
145      * <p>
146      * The contents of the InputStream are
147      * read until the end of the stream is reached, but neither the
148      * source nor the destination are closed.  You must do this yourself
149      * outside of the method call.  The number of bytes read/written is
150      * returned.
151      * <p>
152      * @param source  The source InputStream.
153      * @param dest    The destination OutputStream.
154      * @param bufferSize  The number of bytes to buffer during the copy.
155      * @param streamSize  The number of bytes in the stream being copied.
156      *          Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
157      * @param listener  The CopyStreamListener to notify of progress.  If
158      *      this parameter is null, notification is not attempted.
159      * @exception CopyStreamException  If an error occurs while reading from the
160      *            source or writing to the destination.  The CopyStreamException
161      *            will contain the number of bytes confirmed to have been
162      *            transferred before an
163      *            IOException occurred, and it will also contain the IOException
164      *            that caused the error.  These values can be retrieved with
165      *            the CopyStreamException getTotalBytesTransferred() and
166      *            getIOException() methods.
167      ***/
168     public static final long copyStream(InputStream source, OutputStream dest,
169                                         int bufferSize, long streamSize,
170                                         CopyStreamListener listener)
171     throws CopyStreamException
172     {
173       return copyStream(source, dest, bufferSize, streamSize, listener,
174                         true);
175     }
176 
177 
178     /***
179      * Copies the contents of an InputStream to an OutputStream using a
180      * copy buffer of a given size.  The contents of the InputStream are
181      * read until the end of the stream is reached, but neither the
182      * source nor the destination are closed.  You must do this yourself
183      * outside of the method call.  The number of bytes read/written is
184      * returned.
185      * <p>
186      * @param source  The source InputStream.
187      * @param dest    The destination OutputStream.
188      * @return  The number of bytes read/written in the copy operation.
189      * @exception CopyStreamException  If an error occurs while reading from the
190      *            source or writing to the destination.  The CopyStreamException
191      *            will contain the number of bytes confirmed to have been
192      *            transferred before an
193      *            IOException occurred, and it will also contain the IOException
194      *            that caused the error.  These values can be retrieved with
195      *            the CopyStreamException getTotalBytesTransferred() and
196      *            getIOException() methods.
197      ***/
198     public static final long copyStream(InputStream source, OutputStream dest,
199                                         int bufferSize)
200     throws CopyStreamException
201     {
202         return copyStream(source, dest, bufferSize,
203                           CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
204     }
205 
206 
207     /***
208      * Same as <code> copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
209      ***/
210     public static final long copyStream(InputStream source, OutputStream dest)
211     throws CopyStreamException
212     {
213         return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE);
214     }
215 
216 
217     /***
218      * Copies the contents of a Reader to a Writer using a
219      * copy buffer of a given size and notifies the provided
220      * CopyStreamListener of the progress of the copy operation by calling
221      * its bytesTransferred(long, int) method after each write to the
222      * destination.  If you wish to notify more than one listener you should
223      * use a CopyStreamAdapter as the listener and register the additional
224      * listeners with the CopyStreamAdapter.
225      * <p>
226      * The contents of the Reader are
227      * read until its end is reached, but neither the source nor the
228      * destination are closed.  You must do this yourself outside of the
229      * method call.  The number of characters read/written is returned.
230      * <p>
231      * @param source  The source Reader.
232      * @param dest    The destination writer.
233      * @param bufferSize  The number of characters to buffer during the copy.
234      * @param streamSize  The number of characters in the stream being copied.
235      *          Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
236      * @param listener  The CopyStreamListener to notify of progress.  If
237      *      this parameter is null, notification is not attempted.
238      * @return  The number of characters read/written in the copy operation.
239      * @exception CopyStreamException  If an error occurs while reading from the
240      *            source or writing to the destination.  The CopyStreamException
241      *            will contain the number of bytes confirmed to have been
242      *            transferred before an
243      *            IOException occurred, and it will also contain the IOException
244      *            that caused the error.  These values can be retrieved with
245      *            the CopyStreamException getTotalBytesTransferred() and
246      *            getIOException() methods.
247      ***/
248     public static final long copyReader(Reader source, Writer dest,
249                                         int bufferSize, long streamSize,
250                                         CopyStreamListener listener)
251     throws CopyStreamException
252     {
253         int chars;
254         long total;
255         char[] buffer;
256 
257         buffer = new char[bufferSize];
258         total = 0;
259 
260         try
261         {
262             while ((chars = source.read(buffer)) != -1)
263             {
264                 // Technically, some read(char[]) methods may return 0 and we cannot
265                 // accept that as an indication of EOF.
266                 if (chars == 0)
267                 {
268                     chars = source.read();
269                     if (chars < 0)
270                         break;
271                     dest.write(chars);
272                     dest.flush();
273                     ++total;
274                     if (listener != null)
275                         listener.bytesTransferred(total, chars, streamSize);
276                     continue;
277                 }
278 
279                 dest.write(buffer, 0, chars);
280                 dest.flush();
281                 total += chars;
282                 if (listener != null)
283                     listener.bytesTransferred(total, chars, streamSize);
284             }
285         }
286         catch (IOException e)
287         {
288             throw new CopyStreamException("IOException caught while copying.",
289                                           total, e);
290         }
291 
292         return total;
293     }
294 
295 
296     /***
297      * Copies the contents of a Reader to a Writer using a
298      * copy buffer of a given size.  The contents of the Reader are
299      * read until its end is reached, but neither the source nor the
300      * destination are closed.  You must do this yourself outside of the
301      * method call.  The number of characters read/written is returned.
302      * <p>
303      * @param source  The source Reader.
304      * @param dest    The destination writer.
305      * @param bufferSize  The number of characters to buffer during the copy.
306      * @return  The number of characters read/written in the copy operation.
307      * @exception CopyStreamException  If an error occurs while reading from the
308      *            source or writing to the destination.  The CopyStreamException
309      *            will contain the number of bytes confirmed to have been
310      *            transferred before an
311      *            IOException occurred, and it will also contain the IOException
312      *            that caused the error.  These values can be retrieved with
313      *            the CopyStreamException getTotalBytesTransferred() and
314      *            getIOException() methods.
315      ***/
316     public static final long copyReader(Reader source, Writer dest,
317                                         int bufferSize)
318     throws CopyStreamException
319     {
320         return copyReader(source, dest, bufferSize,
321                           CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
322     }
323 
324 
325     /***
326      * Same as <code> copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
327      ***/
328     public static final long copyReader(Reader source, Writer dest)
329     throws CopyStreamException
330     {
331         return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE);
332     }
333 
334 }