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    }