Package com.enterprisedt.net.ftp

Source Code of com.enterprisedt.net.ftp.FTPInputStream

/**
*
*  Copyright (C) 2007 Enterprise Distributed Technologies Ltd
*
*  www.enterprisedt.com
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public
*  License as published by the Free Software Foundation; either
*  version 2.1 of the License, or (at your option) any later version.
*
*  This library is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*  Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*  Bug fixes, suggestions and comments should be should posted on
*  http://www.enterprisedt.com/forums/index.php
*
*  Change Log:
*
*    $Log: FTPInputStream.java,v $
*    Revision 1.3  2009-09-21 00:53:34  bruceb
*    fix bug where LF were stripped when should have been left in ASCII mode
*
*    Revision 1.2  2008-07-29 02:58:00  bruceb
*    fix read() bug
*
*    Revision 1.1  2007-12-18 07:52:06  bruceb
*    2.0 changes
*
*
*/
package com.enterprisedt.net.ftp;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;

import com.enterprisedt.util.debug.Logger;

/**
*  Represents an input stream of bytes coming from an FTP server, permitting
*  the user to download a file by reading the stream. It can only be used
*  for one download, i.e. after the stream is closed it cannot be reopened.
*
@author      Bruce Blackshaw
@version     $Revision: 1.3 $
*/
public class FTPInputStream extends FileTransferInputStream {
   
    private static Logger log = Logger.getLogger("FTPInputStream");
   
    /**
     * Line separator
     */
    final private static byte[] LINE_SEPARATOR = System.getProperty("line.separator").getBytes();

    /**
     * Interval that we notify the monitor of progress
     */
    private long monitorInterval;
     
    /**
     * The client being used to perform the transfer
     */
    private FTPClient client;
   
    /**
     * The input stream from the FTP server
     */
    private BufferedInputStream in;
   
    /**
     * Number of bytes downloaded
     */
    private long size = 0;
   
    /**
     * Is this an ASCII transfer or not?
     */
    private boolean isASCII = false;
       
    /**
     * Buffer that supplies the stream
     */
    private byte [] buffer;
   
    /**
     * Current position to read from in the buffer
     */
    private int bufpos = 0;
   
    /**
     * The length of the buffer
     */
    private int buflen = 0;
   
    /**
     * Buffer read from the FTP server
     */
    private byte[] chunk;
   
    private byte[] prevBuf = new byte[FTPClient.FTP_LINE_SEPARATOR.length];
   
    private int matchpos = 0;
   
    /**
     * Output stream to write to
     */
    private ByteArrayOutputStream out;
   
    /**
     * Count of byte since last the progress monitor was notified.
     */
    private long monitorCount = 0;

    /**
     * Progress monitor reference
     */
    private FTPProgressMonitor monitor;
   
    /**
     * Progress monitor reference
     */
    private FTPProgressMonitorEx monitorEx;
   
    /**
     * Flag to indicated we've started downloading
     */
    private boolean started = false;
           
    /**
     * Constructor. A connected FTPClient instance must be supplied. This sets up the
     * download
     *
     * @param client            connected FTPClient instance
     * @param remoteFile        remote file
     * @throws IOException
     * @throws FTPException
     */
    public FTPInputStream(FTPClient client, String remoteFile) throws IOException, FTPException {
        this.client = client;
        this.remoteFile = remoteFile;
        try {
            client.initGet(remoteFile);

            // get an input stream to read data from ... AFTER we have
            // the ok to go ahead AND AFTER we've successfully opened a
            // stream for the local file
            in = new BufferedInputStream(new DataInputStream(client.getInputStream()));

        }
        catch (IOException ex) {
            client.validateTransferOnError(ex);
            throw ex;
        }
       
        this.monitorInterval = client.getMonitorInterval();
        this.monitor = client.getProgressMonitor();
        this.chunk = new byte[client.getTransferBufferSize()];
        this.out = new ByteArrayOutputStream(client.getTransferBufferSize());
        this.isASCII = (client.getType().equals(FTPTransferType.ASCII));
    }
   
   
    /**
     * The input stream uses the progress monitor currently owned by the FTP client.
     * This method allows a different progress monitor to be passed in, or for the
     * monitor interval to be altered.
     *
     * @param monitor               progress monitor reference
     * @param monitorInterval      
     */
    public void setMonitor(FTPProgressMonitorEx monitor, long monitorInterval) {
        this.monitor = monitor;
        this.monitorEx = monitor;
        this.monitorInterval = monitorInterval;
    }

    /**
     * Reads the next byte of data from the input stream. The value byte is
     * returned as an int in the range 0 to 255. If no byte is available because
     * the end of the stream has been reached, the value -1 is returned.
     * This method blocks until input data is available, the end of the stream
     * is detected, or an exception is thrown.
     */
    public int read() throws IOException {
        if (!started) {
            start();
        }
        if (buffer == null)
            return -1;
        if (bufpos == buflen) {
            buffer = refreshBuffer();
            if (buffer == null)
                return -1;
        }
        return 0xFF & buffer[bufpos++];
    }
   
    /**
     * Reads up to len bytes of data from the input stream into an array of bytes.
     * An attempt is made to read as many as len bytes, but a smaller number may
     * be read, possibly zero. The number of bytes actually read is returned as an integer.
     * This method blocks until input data is available, end of file is detected,
     * or an exception is thrown.
     *
     * @param b    array to read into
     * @param off  offset into the array to start at
     * @param len  the number of bytes to be read
     *
     * @return  the number of bytes read, or -1 if the end of the stream has been reached.
     */
    public int read(byte b[], int off, int len) throws IOException {
        if (!started) {
            start();
        }
        if (buffer == null || len == 0)
            return -1;
       
        if (bufpos == buflen) {
            buffer = refreshBuffer();
            if (buffer == null)
                return -1;
        }
       
        int available = 0;
        int remaining = len;
        while ( (available = buflen-bufpos) < remaining ) {
            System.arraycopy(buffer, bufpos, b, off, available);
            remaining -= available;
            off += available;
            buffer = refreshBuffer();
            if (buffer == null)
                return len-remaining;
        }
        System.arraycopy(buffer, bufpos, b, off, remaining);
        bufpos += remaining;
        return len;       
    }
   
    /**
     * Start the transfer
     *
     * @throws IOException
     */
    private void start() throws IOException {
        if (monitorEx != null) {
            monitorEx.transferStarted(TransferDirection.DOWNLOAD, remoteFile);
        }
        buffer = refreshBuffer();
        started = true;
    }
   
    /**
     * Refresh the buffer by reading the internal FTP input stream
     * directly from the server
     *
     * @return  byte array of bytes read, or null if the end of stream is reached
     * @throws IOException
     */
    private byte[] refreshBuffer() throws IOException {
        bufpos = 0;
        if (client.isTransferCancelled())
            return null;
        int count = client.readChunk(in, chunk, chunk.length);
        if (count < 0) {
            if (isASCII && matchpos > 0) {              
                size += matchpos;
                buflen = matchpos;
                monitorCount += matchpos;
                byte[] tmp = new byte[matchpos];
                System.arraycopy(tmp, 0, prevBuf, 0, matchpos);
                matchpos = 0;
                return tmp;
            }
            return null;
        }
        try {
            if (!isASCII) {
                size += count;
                monitorCount += count;
                buflen = count;
                return chunk;
            }
            else {
                // transform CRLF
                out.reset();
                for (int i = 0; i < count; i++) {
                    if (chunk[i] == FTPClient.FTP_LINE_SEPARATOR[matchpos]) {
                        prevBuf[matchpos] = chunk[i];
                        matchpos++;
                        if (matchpos == FTPClient.FTP_LINE_SEPARATOR.length) {
                            out.write(LINE_SEPARATOR);
                            size += LINE_SEPARATOR.length;
                            monitorCount += LINE_SEPARATOR.length;
                            matchpos = 0;
                        }
                    }
                    else { // no match
                        // write out existing matches
                        if (matchpos > 0) {
                            out.write(prevBuf, 0, matchpos);
                            size += matchpos;
                            monitorCount += matchpos;
                        }
                        out.write(chunk[i]);
                        size++;
                        monitorCount++;
                        matchpos = 0;
                    }                             
                }               
                byte[] result = out.toByteArray();
                buflen = result.length;
                return result;
            }
        }
        finally {
            if (monitor != null && monitorCount > monitorInterval) {
                monitor.bytesTransferred(size);
                monitorCount = 0
            }   

        }
    }
   

    /**
     * Closes this input stream and releases any system resources associated
     * with the stream. This <b>must</b> be called before any other operations
     * are initiated on the FTPClient.
     *
     * @exception  IOException  if an I/O error occurs.
     */
    public void close() throws IOException {
       
        if (!closed) {
            closed = true;
           
            client.forceResumeOff();
   
            // close streams
            client.closeDataSocket(in);
           
            if (monitor != null)
                monitor.bytesTransferred(size)
   
            // log bytes transferred
            log.debug("Transferred " + size + " bytes from remote host");
           
            try {
                client.validateTransfer();
            }
            catch (FTPException ex) {
                throw new IOException(ex.getMessage());
            }
           
            if (monitorEx != null)
                monitorEx.transferComplete(TransferDirection.DOWNLOAD, remoteFile);
        }
    }
   
}
TOP

Related Classes of com.enterprisedt.net.ftp.FTPInputStream

TOP
Copyright © 2015 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.