Java 自定义FTP连接池

2023-11-13

一、引入FTP包和连接池包

<!-- ftp连接start -->
<dependency>
    <groupId>commons-net</groupId>
    <artifactId>commons-net</artifactId>
    <version>3.5</version>
</dependency>
<!-- ftp连接start -->

<!-- 自定义连接池 start-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.5.0</version>
</dependency>
<!-- 自定义连接池 end-->

二、在项目根路径新建一个配置文件,把连接池配置属性和FTPClient属性配置在配置文件中,ftpClient.properties配置文件如下

#FTP连接池配置
#最大数
ftpClient_maxTotal=50
#最小空闲
ftpClient_minIdle=10
#最大空闲
ftpClient_maxIdle=100
#最大等待时间
ftpClient_maxWait=3000
#池对象耗尽之后是否阻塞,maxWait<0时一直等待
ftpClient_blockWhenExhausted=true
#取对象是验证
ftpClient_testOnBorrow=true
#回收验证
ftpClient_testOnReturn=true
#创建时验证
ftpClient_testOnCreate=true
#空闲验证
ftpClient_testWhileIdle=false
#后进先出
ftpClient_lifo=false

#FTP连接属性配置
#ip
ftpClient_host=192.168.158.98
#端口
ftpClient_port=21
#登录名
ftpClient_username=ftpadmin
#密码
ftpClient_pasword=eakom123456
#连接是否为主动模式
ftpClient_passiveMode=true
#编码
ftpClient_encoding=UTF-8
#超时时间
ftpClient_clientTimeout=600
#线程数
ftpClient_threaNum=1
#文件传送类型
#0=ASCII_FILE_TYPE(ASCII格式) 1=EBCDIC_FILE_TYPE 2=LOCAL_FILE_TYPE(二进制文件)  
ftpClient_transferFileType=2
#是否重命名
ftpClient_renameUploaded=true
#重新连接时间
ftpClient_retryTimes=1200
#缓存大小
ftpClient_bufferSize=1024
#默认进入的路径
ftpClient_workingDirectory=/home/ftpadmin/

三、新建一个FTP客户端属性类

package com.eakom.common.util.ftpPool;
/**
 * FTP属性相关的配置
 * @author eakom
 * @date 2018年1月11日
 */
public class FTPConfig{
    private String host;
    private int port;
    private String username;
    private String password;
    private boolean passiveMode;
    private String encoding;
    private int clientTimeout;
    private int threadNum;
    private int transferFileType;
    private boolean renameUploaded;
    private int retryTimes;
    private int bufferSize;
    private String workingDirectory;


    public String getWorkingDirectory() {
        return workingDirectory;
    }
    public void setWorkingDirectory(String workingDirectory) {
        this.workingDirectory = workingDirectory;
    }
    public int getBufferSize() {
        return bufferSize;
    }
    public void setBufferSize(int bufferSize) {
        this.bufferSize = bufferSize;
    }
    public String getHost() {
        return host;
    }
    public void setHost(String host) {
        this.host = host;
    }
    public int getPort() {
        return port;
    }
    public void setPort(int port) {
        this.port = port;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public boolean getPassiveMode() {
        return passiveMode;
    }
    public void setPassiveMode(boolean passiveMode) {
        this.passiveMode = passiveMode;
    }
    public String getEncoding() {
        return encoding;
    }
    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }
    public int getClientTimeout() {
        return clientTimeout;
    }
    public void setClientTimeout(int clientTimeout) {
        this.clientTimeout = clientTimeout;
    }
    public int getThreadNum() {
        return threadNum;
    }
    public void setThreadNum(int threadNum) {
        this.threadNum = threadNum;
    }
    public int getTransferFileType() {
        return transferFileType;
    }
    public void setTransferFileType(int transferFileType) {
        this.transferFileType = transferFileType;
    }
    public boolean isRenameUploaded() {
        return renameUploaded;
    }
    public void setRenameUploaded(boolean renameUploaded) {
        this.renameUploaded = renameUploaded;
    }
    public int getRetryTimes() {
        return retryTimes;
    }
    public void setRetryTimes(int retryTimes) {
        this.retryTimes = retryTimes;
    }

}

类中的属性与配置文件ftpClient.properties中的属性相对应

四、新建一个FTP客户端工厂类,继承于commons-pool 包中的BasePooledObjectFactory类,并重写create()、 wrap(FTPClient ftpClient)、destroyObject(PooledObject p)和validateObject(PooledObject p)四个方法

package com.eakom.common.util.ftpPool;

import java.io.IOException;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FTPClientFactory extends BasePooledObjectFactory<FTPClient> {
    private static Logger logger = LoggerFactory.getLogger(FTPClientFactory.class);
    private FTPConfig ftpConfig;

    public FTPClientFactory(FTPConfig ftpConfig) {
        this.ftpConfig = ftpConfig;
    }
    /**
     * 新建对象
     */
    @Override
    public FTPClient create() throws Exception {
        FTPClient ftpClient = new FTPClient();
        ftpClient.setConnectTimeout(ftpConfig.getClientTimeout());
        try {
            ftpClient.connect(ftpConfig.getHost(), ftpConfig.getPort());
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                logger.error("FTPServer 拒绝连接");
                return null;
            }
            boolean result = ftpClient.login(ftpConfig.getUsername(),ftpConfig.getPassword());
            if (!result) {
                logger.error("ftpClient登陆失败!");
                throw new Exception("ftpClient登陆失败! userName:"+ ftpConfig.getUsername() + " ; password:"
                        + ftpConfig.getPassword());
            }
            ftpClient.setFileType(ftpConfig.getTransferFileType());
            ftpClient.setBufferSize(ftpConfig.getBufferSize());
            ftpClient.setControlEncoding(ftpConfig.getEncoding());
            if (ftpConfig.getPassiveMode()) {
                ftpClient.enterLocalPassiveMode();
            }
            ftpClient.changeWorkingDirectory(ftpConfig.getWorkingDirectory());
        } catch (IOException e) {
            logger.error("FTP连接失败:", e);
        }
        return ftpClient;
    }

    @Override
    public PooledObject<FTPClient> wrap(FTPClient ftpClient) {
        return new DefaultPooledObject<FTPClient>(ftpClient);
    }

    /**
     * 销毁对象
     */
    @Override
    public void destroyObject(PooledObject<FTPClient> p) throws Exception {
        FTPClient ftpClient = p.getObject();
        ftpClient.logout();
        super.destroyObject(p);
    }

    /**
     * 验证对象
     */
    @Override
    public boolean validateObject(PooledObject<FTPClient> p) {
        FTPClient ftpClient = p.getObject();
        boolean connect = false;
        try {
            connect = ftpClient.sendNoOp();
            if(connect){                
                ftpClient.changeWorkingDirectory(ftpConfig.getWorkingDirectory());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return connect;
    }
}

五、新建FTP连接池类,连接池中有带有一个构造方法,连接器初始化时,自动新建commons-pool包中的GenericObjectPool类,初始化连接池;

package com.eakom.common.util.ftpPool;

import java.io.InputStream;
import java.util.Properties;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;


public class FTPClientPool{
    private GenericObjectPool<FTPClient> ftpClientPool;
    public FTPClientPool(InputStream in){
        Properties pro = new Properties();
        try {
            pro.load(in);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
        // 初始化对象池配置
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setBlockWhenExhausted(Boolean.parseBoolean(pro.getProperty("ftpClient_blockWhenExhausted")));
        poolConfig.setMaxWaitMillis(Long.parseLong(pro.getProperty("ftpClient_maxWait")));
        poolConfig.setMinIdle(Integer.parseInt(pro.getProperty("ftpClient_minIdle")));
        poolConfig.setMaxIdle(Integer.parseInt(pro.getProperty("ftpClient_maxIdle")));
        poolConfig.setMaxTotal(Integer.parseInt(pro.getProperty("ftpClient_maxTotal")));
        poolConfig.setTestOnBorrow(Boolean.parseBoolean(pro.getProperty("ftpClient_testOnBorrow")));
        poolConfig.setTestOnReturn(Boolean.parseBoolean(pro.getProperty("ftpClient_testOnReturn")));
        poolConfig.setTestOnCreate(Boolean.parseBoolean(pro.getProperty("ftpClient_testOnCreate")));
        poolConfig.setTestWhileIdle(Boolean.parseBoolean(pro.getProperty("ftpClient_testWhileIdle")));
        poolConfig.setLifo(Boolean.parseBoolean(pro.getProperty("ftpClient_lifo")));

        FTPConfig ftpConfig=new FTPConfig();
        ftpConfig.setHost(pro.getProperty("ftpClient_host"));
        ftpConfig.setPort(Integer.parseInt(pro.getProperty("ftpClient_port")));
        ftpConfig.setUsername(pro.getProperty("ftpClient_username"));
        ftpConfig.setPassword(pro.getProperty("ftpClient_pasword"));
        ftpConfig.setClientTimeout(Integer.parseInt(pro.getProperty("ftpClient_clientTimeout")));
        ftpConfig.setEncoding(pro.getProperty("ftpClient_encoding"));
        ftpConfig.setWorkingDirectory(pro.getProperty("ftpClient_workingDirectory"));
        ftpConfig.setPassiveMode(Boolean.parseBoolean(pro.getProperty("ftpClient_passiveMode")));
        ftpConfig.setRenameUploaded(Boolean.parseBoolean(pro.getProperty("ftpClient_renameUploaded")));
        ftpConfig.setRetryTimes(Integer.parseInt(pro.getProperty("ftpClient_retryTimes")));
        ftpConfig.setTransferFileType(Integer.parseInt(pro.getProperty("ftpClient_transferFileType")));
        ftpConfig.setBufferSize(Integer.parseInt(pro.getProperty("ftpClient_bufferSize")));
        // 初始化对象池
        ftpClientPool = new GenericObjectPool<FTPClient>(new FTPClientFactory(ftpConfig), poolConfig);
    }
    public FTPClient borrowObject() throws Exception {
    /*  System.out.println("获取前");
        System.out.println("活动"+ftpClientPool.getNumActive());
        System.out.println("等待"+ftpClientPool.getNumWaiters());
        System.out.println("----------");*/
        return ftpClientPool.borrowObject();
    }
    public void returnObject(FTPClient ftpClient) {

        /*System.out.println("归还前");
        System.out.println("活动"+ftpClientPool.getNumActive());
        System.out.println("等待"+ftpClientPool.getNumWaiters());
        System.out.println("----------");*/
        ftpClientPool.returnObject(ftpClient);
        System.out.println("归还后");
        System.out.println("活动"+ftpClientPool.getNumActive());
        System.out.println("等待"+ftpClientPool.getNumWaiters());
        System.out.println("----------");
    }
}

六、测试连接池
同时启动多个线程,观察连接池内,FTPClient的数量的变化

package com.eakom.common.util.ftpPool;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

import org.apache.commons.net.ftp.FTPClient;

public class Ftp {
    private static FTPClientPool ftpClientPool;
    static{
//      ftpClientPool=new FTPClientPool(Thread.currentThread().getContextClassLoader().getResourceAsStream("ftpClient.properties"));
        ftpClientPool=new FTPClientPool(Ftp.class.getClassLoader().getResourceAsStream("ftpClient.properties"));
    }
    public static void main(String[] args) {
        for(int i=0;i<50;i++){
            Thread thread=new Thread(new Runnable() {
                @Override
                public void run() {
                    sendFile();
                }
            });
            thread.start();
            try {
                thread.sleep(15);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }


    }
    public static void sendFile(){
        long start = System.currentTimeMillis();
        InputStream inputStream = null;
        FTPClient ftpClient = null;
        try {
            ftpClient = ftpClientPool.borrowObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            String path="C:/Users/Administrator/Desktop/44/中文.txt";
            File file = new File(path);
            ftpClient.changeWorkingDirectory("/home/ftpadmin/aa");
            inputStream = new FileInputStream(file);


                String fileName =new Date().getSeconds()+new Date().getSeconds()+".txt";
                boolean flag = ftpClient.storeFile(new String(fileName.getBytes("GBK"), "iso-8859-1") , inputStream);
                long end = System.currentTimeMillis();
                System.out.println("**********************************************"+flag);
                long lo=end-start;
                System.out.println("耗时:"+lo);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            ftpClientPool.returnObject(ftpClient);          
        }
    }
}

至此,FTPClient连接创建完成,如果问题,欢迎大家指正,谢谢!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 自定义FTP连接池 的相关文章

  • PHP定时访问api解决方案【已测试通过】

    背景介绍 今天打算做一个数据统计功能 由于数据结构复杂 无法通过存储过程来完成 所以只能开发PHP功能 定时调用该功能以完成数据统计 方案1 创建Windows计划任务 定时执行 bat批处理文件 具体实施方法 先创建一个 bat文件 例如

随机推荐

  • vue2 升级到 vue3 router 动态授权路由 异步加载报错 TypeError: Cannot read properties of undefined (reading ‘apply‘)

    使用 resolve gt require views item component resolve 会报错 TypeError Cannot read properties of undefined reading apply 我的解决历
  • 替换字符串中指定的字符串

    例如下面的例子 有时需要把某个字符串中的部分字符替换成另一个字符 可以使用std string 自带的函数replace replace第一个参数为起点 第二个为替换的长度 第三个为替换为的内容 for auto inventoryStat
  • 跟我学Spring Cloud(2020.0.0-M6版)-01-服务注册与服务发现-Eureka Server

    目录 1 所需要版本 2 创建基于web的Maven项目 SpringCloud 的服务注册中心 3 检查IntelliJ IDEA 的环境配置 4 检查java verison配置 5 检查Edit Configurations配置 6
  • 区块链技术基本概念

    链客 专为开发者而生 有问必答 此文章来自链客区块链技术问答社区 未经允许拒绝转载 区块链技术根本概念 了解这些名词是一个不错的开端 公钥加密系统 Alice有一把公钥和一把私钥 她可以用她的私钥创建数字签名 而Bob可以用她的公钥来验证这
  • 自定义 swap 函数

    背景 STL 中提供了 swap 算法 用于交换两个对象的值 其一般实现方法如下 namespace std template
  • c语言缩进用tab还是空格,程序员编码首行缩进使用Tab键好还是空格好?

    本文转载自CocoaChina 每个程序员都有自己喜欢的编码风格以及编码习惯 那么 问题来了 一个很常用也很简单的问题 让程序员分为两派 编程时 到时是使用Tab按键来进行首行缩进好呢还是敲空格按键好呢 少侠 别急 带老夫给你慢慢分析 Ta
  • Git入门与使用 (二) Git相关命令的介绍与使用

    文章目录 一 前言 二 理解Git的工作区 暂存区 本地仓库和远程仓库 三 Git相关命令的介绍与使用 1 初始化Git仓库 2 设置签名 2 1 设置仓库 项目级别的签名 2 2 设置系统用户级别的签名 3 查看Git仓库的状态 4 向暂
  • [转]Windows下安全权限设置详解

    一 Windows下安全权限设置详解 简 介 随着动网论坛的广泛应用和动网上传漏洞的被发现以及SQL注入式攻击越来越多的被使用 WEBSHELL让防火墙形同虚设 一台即使打了所有微软补丁 只让80端口对外开放的WEB服务器也逃不过被黑的命运
  • 刷脸庞大的交易市场从而也带来新的商机

    现在我们外出买东西付款 已经有了非常便捷的扫码支付功能 这个功能不仅是年轻人喜欢使用 就连中老年人也跟上的时代的步伐 许多超市 便利店已经菜市场 都能够看到二维码的身影 但是随着时代不断地进步 扫码付款这一新兴方式 接二连三地被曝出许多风险
  • Unity自动滚动字幕的实现

    Unity自动滚动字幕的实现 首先按照图片里的进行创建 然后用代码获取Scrollbar 在将Value值一直变为1 using System Collections using System Collections Generic usi
  • Jupyter程序安装和使用指南【操作示例】

    Jupyter Notebook 简称Jupyter 是一个交互式编辑器 它支持运行40多种编程语言 便于创建和共享文档 Jupyter本质上是一个Web应用程序 与其他编辑器相比 它具有小巧 灵活 支持实时代码 方便图表展示等优点 下面分
  • ECCV 2020 Representation Learning on Visual-Symbolic Graphs for Video Understanding

    动机 自然视频中的事件通常产生于演员和目标之间的时空交互 并且涉及多个共同发生的活动和目标类 因此 需要开发能够对时空视觉和语义上下文进行有效建模的算法 捕捉这种上下文的一种方法是使用基于图的建模 它在计算机视觉中有着丰富的历史 传统的基于
  • qt day3

  • java自动装配_Spring中自动装配的4种方式

    Spring容器可以在不使用和元素的情况下自动装配相互协作的bean之间的关系 助于减少编写一个大的基于Spring的应用程序的XML配置的数量使用元素的autowire属性为一个bean定义指定自动装配模式 在Spring中 我们有4种方
  • 计算机网络期末总结复习(全)

    文章目录 第一章 概述 1 1 计算机网络在信息时代的作用 我国互联网发展状况 1 2 因特网概述 1 网络 互连网 互联网 和因特网 2 因特网发展的三个阶段 3 因特网的标准化工作 4 因特网的组成 补充
  • 78页PPT全面揭示互联网与传统行业的融合与碰撞

    正如报告的主题 融合与碰撞 移动互联网和传统行业正在融合与碰撞之间进行行业重塑 纵观教育行业 现阶段已经有四种运营模式逐渐成熟 但仍存在自身问题和很多外部矛盾 找准发展趋势意义重大 一起来看看水深火热的TMT产业发展趋势吧
  • 【前端demo】背景渐变动画

    文章目录 效果 过程 代码 html css 其他demo 效果 效果预览 https codepen io karshey pen OJrXZwQ 过程 注意 直接在body上加height 100 可能也会出现height为0的情况 这
  • docker修改服务器参数怎么办,Docker(32)- 如何修改 docker 容器的启动参数

    如果你还想从头学起 Docker 可以看看这个系列的文章哦 前言 有时候创建容器时忘了添加 restart 参数 导致 Docker 服务重启后 容器不会自动启动 每次都需要手动启动 很不方便 那现在如何针对已创建的容器修改 restart
  • LeetCode——动态规划篇(二)

    刷题顺序及思路来源于代码随想录 网站地址 https programmercarl com 目录 343 整数拆分 力扣 LeetCode 96 不同的二叉搜索树 力扣 LeetCode 416 分割等和子集 力扣 LeetCode 104
  • Java 自定义FTP连接池

    一 引入FTP包和连接池包