转自:https://blog.csdn.net/eakom/article/details/79038590java
1、引入FTP包和链接池包apache
<!-- 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-->
2、在项目根路径新建一个配置文件,把链接池配置属性和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/
3、新建一个FTP客户端属性类markdown
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中的属性相对应ide
4、新建一个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; } }
5、新建FTP链接池类,链接池中有带有一个构造方法,链接器初始化时,自动新建commons-pool包中的GenericObjectPool类,初始化链接池;this
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("----------"); } }
6、测试链接池
同时启动多个线程,观察链接池内,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); } } }