FTP线程池

1.背景

>由于项目中需要使用Ftp进行资源文件的摆渡,网上看了具体实现,发现较多问题,因此重新写一篇用于参考。

2.代码

2.1 POM依赖

项目使用了apache.commons.pool进行线程池的创建与工厂的时间

      <dependency>
            <groupId>commons-pool</groupId>
            <artifactId>commons-pool</artifactId>
             <version>1.6</version>
        </dependency>

2.2 代码实现

1.首先创建一个工厂类用于创建FtpClient。

@Slf4j
@SuppressWarnings("all")
public class FTPClientFactory implements PoolableObjectFactory<FTPClient> {

    private FTPConfigPro ftpProperties;

    public FTPClientFactory(FTPConfigPro ftpProperties) {
        this.ftpProperties = ftpProperties;
    }

    /**
     * 创建实体
     * @return
     * @throws Exception
     */
    @Override
    public FTPClient makeObject() throws Exception {
        FTPClient ftpClient = new FTPClient();
        ftpClient.setControlEncoding(ftpProperties.getEncoding());
        ftpClient.setConnectTimeout(ftpProperties.getClientTimeout());
        try {
            ftpClient.connect(ftpProperties.getIp(), ftpProperties.getPort());
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                log.warn("FTPServer refused connection");
                return null;
            }
            boolean result = ftpClient.login(ftpProperties.getUser(), ftpProperties.getPass());
            ftpClient.setFileType(ftpProperties.getTransferFileType());
            //Linux下模式必须设置
            ftpClient.enterLocalPassiveMode();
            if (!result) {
                log.warn("ftpClient login failed... username is {}", ftpProperties.getUser());
            }
        } catch (Exception e) {
            log.error("create ftp connection failed...{}", e);
            throw e;
        }

        return ftpClient;
    }

    /**
     * 回收实体
     * @param ftpClient
     * @throws Exception
     */
    @Override
    public void destroyObject(FTPClient ftpClient) throws Exception {
        try {
            if(ftpClient != null && ftpClient.isConnected()) {
                ftpClient.logout();
            }
        } catch (Exception e) {
            log.error("ftp client logout failed...{}", e);
            throw e;
        } finally {
            if(ftpClient != null) {
                ftpClient.disconnect();
            }
        }

    }

    /**
     * 验证对象有效性
     * @param ftpClient
     * @return
     */
    @Override
    public boolean validateObject(FTPClient ftpClient) {
        try {
            return ftpClient.sendNoOp();
        } catch (Exception e) {
            log.error("Failed to validate client: {}");
        }
        return false;
    }

    @Override
    public void activateObject(FTPClient obj) throws Exception {
        //Do nothing

    }

    @Override
    public void passivateObject(FTPClient obj) throws Exception {
        //Do nothing

    }
}

2.对象池的实现,继承ObjectPool

public class FTPClientPool implements ObjectPool<FTPClient> {

    public static final int DEFAULT_POOL_SIZE = 10;

    public BlockingQueue<FTPClient> blockingQueue;

    private FTPClientFactory factory;

    public FTPClientPool(FTPClientFactory factory) throws Exception {
        this(DEFAULT_POOL_SIZE, factory);
    }

    public FTPClientPool(int poolSize, FTPClientFactory factory) throws Exception {
        this.factory = factory;
        this.blockingQueue = new ArrayBlockingQueue<FTPClient>(poolSize);
        initPool(poolSize);
    }

    /**
     * 初始化连接池
     *
     * @param maxPoolSize 最大连接数
     * @throws Exception
     */
    private void initPool(int maxPoolSize) throws Exception {
        int count = 0;
        while (count < maxPoolSize) {
            this.addObject();
            count++;
        }
    }

    /**
     * 从连接池中获取对象
     */
    @Override
    public FTPClient borrowObject() throws Exception {
        log.info("borrowObject ,blockingQueue size:{}",blockingQueue.size());
        FTPClient client = blockingQueue.poll(1,TimeUnit.MINUTES);
        if (client == null) {
            this.addObject();
            log.info("client==null ");
            client=borrowObject();
        } else if (!factory.validateObject(client)) {
            log.info("get validateObject is:false");
            //invalidateObject(client);
            try {
                factory.destroyObject(client);
            } catch (Exception e) {
                //e.printStackTrace();
                log.info("invalidateObject error:{}",e);
            }
            //制造并添加新对象到池中
            log.info("addObject client");
            this.addObject();
            log.info("borrowObject. again");
            client=borrowObject();
        }
        return client;
    }

    /**
     * 返还一个对象(链接)
     */
    @Override
    public void returnObject(FTPClient client) throws Exception {
        log.info("returnObject before blockingQueue size:{}",blockingQueue.size());
        if ((client != null)) {
            if (!blockingQueue.offer(client, 1, TimeUnit.SECONDS)) {
                log.info("returnObject offer time out,blockingQueue size:{}",blockingQueue.size());
                try {
                    factory.destroyObject(client);
                } catch (Exception e) {
                    throw e;
                }
            }

        }
    }

    /**
     * 移除无效的对象(FTP客户端)
     */
    @Override
    public void invalidateObject(FTPClient client) throws Exception {
        blockingQueue.remove(client);
    }

    /**
     * 增加一个新的链接,超时失效
     */
    @Override
    public void addObject() throws Exception {
        blockingQueue.offer(factory.makeObject(), 2, TimeUnit.MINUTES);
    }


    /**
     * 重新连接
     */
    public FTPClient reconnect() throws Exception {
        return factory.makeObject();
    }

    /**
     * 获取空闲链接数(这里暂不实现)
     */
    @Override
    public int getNumIdle() {
        return blockingQueue.size();
    }

    /**
     * 获取正在被使用的链接数
     */
    @Override
    public int getNumActive() {
        return DEFAULT_POOL_SIZE - getNumIdle();
    }

    @Override
    public void clear() throws Exception {

    }

    /**
     * 关闭连接池
     */
    @Override
    public void close() {
        try {
            while (blockingQueue.iterator().hasNext()) {
                FTPClient client = blockingQueue.take();
                factory.destroyObject(client);
            }
        } catch (Exception e) {
            log.error("close ftp client pool failed...{}", e);
        }
    }



    @Override
    public void setFactory(PoolableObjectFactory<FTPClient> poolableObjectFactory) throws IllegalStateException, UnsupportedOperationException {

    }
}

3.ftp工具类

提供ftp操作,上传、下载、读取文件列表等操作。

@Slf4j
public class FTPUtils {

    /**
     * FTP的连接池
     */
    public FTPClientPool ftpClientPool;

    private FTPConfigPro ftpProperties;

    public FTPUtils(FTPConfigPro ftpProperties) {
        this.ftpProperties = ftpProperties;
        init();
    }

    /**
     * 初始化设置
     *
     * @return
     */
    public boolean init() {
        FTPClientFactory factory = new FTPClientFactory(ftpProperties);
        try {
            ftpClientPool = new FTPClientPool(factory);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 获取连接对象
     *
     * @return
     */
    public FTPClient getFTPClient() {
        try {
            FTPClient ftpClient = ftpClientPool.borrowObject();
            ftpClient.changeWorkingDirectory("/");
            return ftpClient;
        } catch (Exception e) {
            log.error("getFTPClient", e.getCause());
            return null;
        }
    }

    /**
     * 当前命令执行完成命令完成
     *
     * @throws IOException
     */
    public void complete(FTPClient ftpClient) throws IOException {
        ftpClient.completePendingCommand();
    }

    /**
     * 当前线程任务处理完成,加入到队列的最后
     *
     * @return
     */
    public void disconnect(FTPClient ftpClient) {
        if (ftpClient != null) {
            try {
                ftpClientPool.returnObject(ftpClient);
            } catch (Exception e) {
                log.error("disconnect,error:", e.getCause());
            }
        }

    }

    /**
     * Description: 向FTP服务器上传文件
     *
     * @param remoteFile 上传到FTP服务器上的文件名
     * @param input      本地文件流
     * @return 成功返回true,否则返回false
     * @Version1.0
     */
    public boolean uploadFile(String remoteFile, InputStream input) {
        boolean result = false;
        FTPClient ftpClient = getFTPClient();
        if (ftpClient == null) {
            log.error("uploadFile getFTPClient is null");
            return false;
        }
        try {
            result = ftpClient.storeFile(remoteFile, input);
            if (!result) {
                log.error("uploadFile file {} error:{}",remoteFile,ftpClient.getReplyString());
            }
        } catch (Exception e) {
            log.error("uploadFile  error:{}",e.getCause());
        }finally {
             Util.closeQuietly(input);
             disconnect(ftpClient);
        }
        return result;
    }

    /**
     * Description: 向FTP服务器上传文件
     *
     * @param remoteFile 上传到FTP服务器上的文件名
     * @param localFile  本地文件
     * @return 成功返回true,否则返回false
     * @Version1.0
     */
    public boolean uploadFile(String remoteFile, String localFile) {
        FileInputStream input = null;
        try {
            input = new FileInputStream(new File(localFile));
        } catch (FileNotFoundException e) {
            log.error("FileNotFoundException:{},error:{}",localFile,e);
        }
        return uploadFile(remoteFile, input);
    }

    /**
     * 拷贝文件
     *
     * @param fromFile
     * @param toFile
     * @return
     * @throws Exception
     */
    public boolean copyFile(String fromFile, String toFile) {

        InputStream in = getFileInputStream(fromFile);
        FTPClient ftpClient = getFTPClient();
        if (ftpClient == null) {
            log.error("copyFile getFTPClient is null");
            return false;
        }
        boolean flag = false;
        try {
            flag = ftpClient.storeFile(toFile, in);
            in.close();
        } catch (IOException e) {
            log.error("ftpClient IOException", e.getCause());
        } finally {
            Util.closeQuietly(in);
            disconnect(ftpClient);
        }
        return flag;
    }

    /**
     * 获取文件输入流
     *
     * @param fileName
     * @return
     * @throws IOException
     */
    public InputStream getFileInputStream(String fileName) {
        ByteArrayOutputStream fos = new ByteArrayOutputStream();
        FTPClient ftpClient = getFTPClient();
        if (ftpClient == null) {
            log.error("getFileInputStream getFTPClient is null");
            return null;
        }

        ByteArrayInputStream in = null;
        try {
            ftpClient.retrieveFile(fileName, fos);
            in = new ByteArrayInputStream(fos.toByteArray());
            fos.close();
        } catch (IOException e) {
            log.error("ftp getFileInputStream", e.getCause());
        } finally {
            disconnect(ftpClient);
        }
        return in;
    }

    /**
     * Description: 从FTP服务器下载文件
     *
     * @return
     * @Version1.0
     */
    public boolean downFile(String remoteFile, String localFile) {
        boolean result = false;
        FTPClient ftpClient = getFTPClient();
        if (ftpClient == null) {
            log.error("downFile getFTPClient is null");
            return false;
        }
        OutputStream os = null;
        try {
            os= new FileOutputStream(localFile);
            ftpClient.retrieveFile(remoteFile, os);
            result = true;
        } catch (Exception e) {
            log.error("downFile ", e.getCause());
        } finally {
            Util.closeQuietly(os);
            disconnect(ftpClient);
        }
        return result;
    }

    /**
     * 从ftp中获取文件流
     *
     * @param filePath
     * @return
     * @throws Exception
     */
    public InputStream getInputStream(String filePath) {
        FTPClient ftpClient = getFTPClient();
        if (ftpClient == null) {
            log.error("getInputStream getFTPClient is null");
            return null;
        }
        InputStream inputStream = null;
        try {
            inputStream = ftpClient.retrieveFileStream(filePath);
        } catch (IOException e) {
            log.error("getInputStream ", e.getCause());
        } finally {
            disconnect(ftpClient);
        }
        return inputStream;
    }

    /**
     * ftp中文件重命名
     *
     * @param fromFile
     * @param toFile
     * @return
     * @throws Exception
     */
    public boolean rename(String fromFile, String toFile) {
        FTPClient ftpClient = getFTPClient();
        if (ftpClient == null) {
            log.error("rename getFTPClient is null");
            return false;
        }
        boolean result = false;
        try {
            result = ftpClient.rename(fromFile, toFile);
        } catch (IOException e) {
            log.error("rename ", e.getCause());
        } finally {
            disconnect(ftpClient);
        }
        return result;
    }

    /**
     * 获取ftp目录下的所有文件
     *
     * @param dir
     * @return
     */
    public FTPFile[] getFiles(String dir) {
        FTPClient ftpClient = getFTPClient();
        if (ftpClient == null) {
            log.error("getFiles getFTPClient is null");
            return null;
        }

        FTPFile[] files = new FTPFile[0];
        try {
            files = new FTPFile[0];
            files = ftpClient.listFiles(dir);
        } catch (IOException e) {
            log.error("获取ftp目录下的所有文件", e.getCause());
        } finally {
            disconnect(ftpClient);
        }

        return files;
    }

    /**
     * 获取ftp目录下的某种类型的文件
     *
     * @param dir
     * @param filter
     * @return
     */
    public FTPFile[] getFiles(String dir, FTPFileFilter filter) {
        FTPClient ftpClient = getFTPClient();
        if (ftpClient == null) {
            log.error("getFiles getFTPClient is null");
            return null;
        }

        FTPFile[] files = new FTPFile[0];
        try {
            files = new FTPFile[0];
            files = ftpClient.listFiles(dir, filter);
        } catch (IOException e) {
            log.error("获取ftp目录下的某种类型的文件", e.getCause());
        } finally {
            disconnect(ftpClient);
        }

        return files;
    }

    /**
     * 创建文件夹
     *
     * @param remoteDir
     * @return 如果已经有这个文件夹返回false
     */
    public boolean makeDirectory(String remoteDir) {
        FTPClient ftpClient = getFTPClient();
        if (ftpClient == null) {
            log.error("makeDirectory getFTPClient is null");
            return false;
        }

        boolean result = false;
        try {
            result = ftpClient.makeDirectory(remoteDir);
        } catch (IOException e) {
            log.error("创建文件夹", e.getCause());
        } finally {
            disconnect(ftpClient);
        }
        return result;
    }

    public boolean mkDirs(String dir) {
        boolean result = false;
        if (null == dir) {
            return result;
        }
        FTPClient ftpClient = getFTPClient();
        if (ftpClient == null) {
            log.error("mkdirs getFTPClient is null");
            return false;
        }

        try {
            ftpClient.changeWorkingDirectory("/");
            StringTokenizer dirs = new StringTokenizer(dir, File.separator);
            String temp = null;
            while (dirs.hasMoreElements()) {
                temp = dirs.nextElement().toString();
                //创建目录
                ftpClient.makeDirectory(temp);
                //进入目录
                ftpClient.changeWorkingDirectory(temp);
                result = true;
            }
            ftpClient.changeWorkingDirectory("/");
        } catch (Exception e) {
            log.error("ftp mkdirs", e.getCause());
        } finally {
            disconnect(ftpClient);
        }

        return result;
    }

    public boolean removeDirectoryALLFile(String pathName){
        boolean result = false;
        if (null == pathName) {
            return result;
        }
        FTPClient ftpClient = getFTPClient();
        if (ftpClient == null) {
            log.error("mkdirs getFTPClient is null");
            return result;
        }
        try {
            ftpClient.changeWorkingDirectory("/");
            FTPFile[] files = ftpClient.listFiles(pathName);
            if (null != files && files.length > 0){
                for (FTPFile file : files) {
                    if (file.isDirectory()) {
                        removeDirectoryALLFile(pathName + File.separator + file.getName());
                    } else{
                        result=ftpClient.deleteFile(pathName + File.separator + file.getName());
                        if (!result){
                            log.error("删除指定文件" + pathName + "/" + file.getName() + "失败!");
                            continue;
                        }
                    }
                }
            }
            ftpClient.changeWorkingDirectory(File.separator+pathName.substring(0, pathName.lastIndexOf(File.separator)));
            result=ftpClient.removeDirectory(File.separator+pathName);
            return result;
        } catch (IOException e){
            log.error("删除指定文件夹" + pathName + "失败:" + e);
            return false;
        }finally {
            disconnect(ftpClient);
        }
    }

    public boolean changeWorkingDirectory(String dir) {
        boolean result = false;
        if (null == dir) {
            return result;
        }
        FTPClient ftpClient = getFTPClient();
        if (ftpClient == null) {
            log.error("changeWorkingDirectory getFTPClient is null");
            return false;
        }
        try {
            ftpClient.changeWorkingDirectory("/");
            result = ftpClient.changeWorkingDirectory(dir);
        } catch (Exception e) {
            log.error("ftp changeWorkingDirectory", e.getCause());
        } finally {
            disconnect(ftpClient);
        }
        return result;
    }

    public void destroy() {
        ftpClientPool.close();
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值