001    /*
002     * JAPI - (Yet another (hopefully) useful) Java API
003     *
004     * Copyright (C) 2006 Christian Hujer
005     *
006     * This program is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU General Public License as
008     * published by the Free Software Foundation; either version 2 of the
009     * License, or (at your option) any later version.
010     *
011     * This program is distributed in the hope that it will be useful, but
012     * WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * General Public License for more details.
015     *
016     * You should have received a copy of the GNU General Public License
017     * along with this program; if not, write to the Free Software
018     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
019     * 02111-1307, USA.
020     */
021    
022    package net.sf.japi.io;
023    
024    import java.io.InputStream;
025    import java.io.OutputStream;
026    import java.io.IOException;
027    
028    /** A Runnable that copies from an InputStream to an OutputStream.
029     * @author <a href="mailto:chris@riedquat.de">Christian Hujer</a>
030     */
031    public class Copier implements Runnable {
032    
033        /** Default buffer size when copying. */
034        public static final int DEFAULT_BUF_SIZE = 8192;
035    
036        /** Default automatic flush. */
037        public static final boolean DEFAULT_AUTO_FLUSH = true;
038    
039        /** Default automatic close. */
040        public static final boolean DEFAULT_AUTO_CLOSE = true;
041    
042        /** The InputStream to read from. */
043        private final InputStream in;
044    
045        /** The OutputStream to write to. */
046        private final OutputStream out;
047    
048        /** The buffer size to use. */
049        private final int bufSize;
050    
051        /** Whether to flush automatically. */
052        private final boolean autoFlush;
053    
054        /** Whether to close streams automatically after copying. */
055        private final boolean autoClose;
056    
057        /** Create a Copier with default buffer size and autoFlush.
058         * @param in the InputStream to read from
059         * @param out the OutputStream to write to
060         */
061        public Copier(final InputStream in, final OutputStream out) {
062            this(in, out, DEFAULT_BUF_SIZE, DEFAULT_AUTO_FLUSH, DEFAULT_AUTO_CLOSE);
063        }
064    
065        /** Create a Copier with specified buffer size and automatic flush behaviour.
066         * @param in the InputStream to read from
067         * @param out the OutputStream to write to
068         * @param bufSize buffer size to use while copying
069         */
070        public Copier(final InputStream in, final OutputStream out, final int bufSize) {
071            this(in, out, bufSize, DEFAULT_AUTO_FLUSH, DEFAULT_AUTO_CLOSE);
072        }
073    
074        /** Create a Copier with specified buffer size and specified flush behaviour.
075         * @param in the InputStream to read from
076         * @param out the OutputStream to write to
077         * @param bufSize buffer size to use while copying
078         * @param autoFlush whether to flush automatically (true for automatic flush, false for flush on close)
079         * @param autoClose whether to close the streams automatically (true for automatic close, false for no close)
080         */
081        public Copier(final InputStream in, final OutputStream out, final int bufSize, final boolean autoFlush, final boolean autoClose) {
082            this.in = in;
083            this.out = out;
084            this.bufSize = bufSize;
085            this.autoFlush = autoFlush;
086            this.autoClose = autoClose;
087        }
088    
089        /** Start the copier in a new thread.
090         * @return the newly created thread
091         */
092        public Thread start() {
093            final Thread thread = new Thread(this);
094            thread.start();
095            return thread;
096        }
097    
098        /** {@inheritDoc} */
099        public void run() {
100            final byte[] buf = new byte[bufSize];
101            try {
102                for (int bytesRead; (bytesRead = in.read(buf)) != -1;) {
103                    out.write(buf, 0, bytesRead);
104                    if (autoFlush) {
105                        out.flush();
106                    }
107                }
108            } catch (final IOException e) {
109                System.err.println(e);
110            } finally {
111                //noinspection CatchGenericClass,OverlyBroadCatchBlock
112                try { out.flush(); } catch (final Exception ignore) { /* ignore */ }
113                if (autoClose) {
114                    //noinspection CatchGenericClass,OverlyBroadCatchBlock
115                    try { out.close(); } catch (final Exception ignore) { /* ignore */ }
116                    //noinspection CatchGenericClass,OverlyBroadCatchBlock
117                    try { in.close(); } catch (final Exception ignore) { /* ignore */ }
118                }
119            }
120        }
121    
122    } // class Copier