java实现ftp连接池ftp-client-pool

首先引入maven依赖

<!-- apache ftp支持 -->
<dependency>
    <groupId>commons-net</groupId>
    <artifactId>commons-net</artifactId>
    <version>3.6</version>
</dependency>
<!-- apache 连接池支持 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.6.0</version>
</dependency>

 

FtpPoolConfi.java

package cn.itsub.code.utils.ftp;

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

/**
 * ftp配置参数对象
 * @author IT夏老师
 */
@Data
public class FtpPoolConfig extends GenericObjectPoolConfig<FTPClient> {

	private String host;// 主机名
	private int port = 21;// 端口
	private String username;// 用户名
	private String password;// 密码
	private int connectTimeOut = 5000;// ftp 连接超时时间 毫秒
	private String controlEncoding = "utf-8";
	private int bufferSize = 1024;// 缓冲区大小
	private int fileType = 2;// 传输数据格式 2表binary二进制数据
	private int dataTimeout = 120000;
	private boolean useEPSVwithIPv4 = false;
	private boolean passiveMode = true;// 是否启用被动模式
	private long poolEvictInterval = 30000; //连接池空闲检测周期

}

 

FtpClientFactory.java

package cn.itsub.code.utils.ftp;

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;

/**
 * ftpclient 工厂
 * @author IT夏老师
 */
public class FTPClientFactory extends BasePooledObjectFactory<FTPClient> {
	
    private static Logger logger = LoggerFactory.getLogger(FTPClientFactory.class);
    
    private FtpPoolConfig ftpPoolConfig;
    
    public FTPClientFactory(FtpPoolConfig config) {
    	this.ftpPoolConfig=config;
    }
   
	public FtpPoolConfig getFtpPoolConfig() {
		return ftpPoolConfig;
	}

	public void setFtpPoolConfig(FtpPoolConfig ftpPoolConfig) {
		this.ftpPoolConfig = ftpPoolConfig;
	}

	//新建对象
    @Override
    public FTPClient create() throws Exception {
        FTPClient ftpClient = new FTPClient();
        ftpClient.setConnectTimeout(ftpPoolConfig.getConnectTimeOut());
        try {
        	
        	logger.info("连接ftp服务器:" +ftpPoolConfig.getHost()+":"+ftpPoolConfig.getPort());
        	ftpClient.connect(ftpPoolConfig.getHost(), ftpPoolConfig.getPort());
            
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                logger.error("FTPServer 拒绝连接");
                return null;
            }
            boolean result = ftpClient.login(ftpPoolConfig.getUsername(),ftpPoolConfig.getPassword());
            if (!result) {
                logger.error("ftpClient登录失败!");
                throw new Exception("ftpClient登录失败! userName:"+ ftpPoolConfig.getUsername() + ", password:"
                        + ftpPoolConfig.getPassword());
            }

			ftpClient.setControlEncoding(ftpPoolConfig.getControlEncoding());
			ftpClient.setBufferSize(ftpPoolConfig.getBufferSize());
			ftpClient.setFileType(ftpPoolConfig.getFileType());
			ftpClient.setDataTimeout(ftpPoolConfig.getDataTimeout());
			ftpClient.setUseEPSVwithIPv4(ftpPoolConfig.isUseEPSVwithIPv4());
			if(ftpPoolConfig.isPassiveMode()){
				logger.info("进入ftp被动模式");
				ftpClient.enterLocalPassiveMode();//进入被动模式
			}
        } 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);
        logger.info("destroyObject");
    }

    /**
     * 验证对象
     */
    @Override
    public boolean validateObject(PooledObject<FTPClient> p) {
        FTPClient ftpClient = p.getObject();
        boolean connect = false;
        try {
            connect = ftpClient.sendNoOp();
            logger.info("validateObject:"+connect);
        } catch (IOException e) {
        	logger.error("验证ftp连接对象,返回false");
        }
        return connect;
    }


   
}

 

FtpClientPool.java

package cn.itsub.code.utils.ftp;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Timer;
import java.util.TimerTask;

/**
 * FTP 客户端连接池
 * @author IT夏老师
 */
public class FTPClientPool {

	private static Logger logger = LoggerFactory.getLogger(FTPClientPool.class);
	Timer timer = new Timer();

	//ftp客户端连接池
	private GenericObjectPool<FTPClient> pool;

	//ftp客户端工厂
	private FTPClientFactory clientFactory;

	/**
	 * 构造函数中 注入一个bean
	 * @param clientFactory
	 */
	public FTPClientPool(FTPClientFactory clientFactory) {
		this.clientFactory = clientFactory;
		pool = new GenericObjectPool<FTPClient>(clientFactory, clientFactory.getFtpPoolConfig());
		pool.setTestWhileIdle(true); //启动空闲检测
		//30秒间隔的心跳检测

		long period = clientFactory.getFtpPoolConfig().getPoolEvictInterval();
		timer.schedule(new TimerTask() {
			public void run() {
				try {
					pool.evict();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		},1000,period);

	}

	public FTPClientFactory getClientFactory() {
		return clientFactory;
	}

	public GenericObjectPool<FTPClient> getPool() {
		return pool;
	}

	/**
	 * 从池子中借一个连接对象
	 * @return (借来的FTPClient对象)
	 * @throws Exception (异常)
	 */
	public FTPClient borrowObject() throws Exception {
		FTPClient client = pool.borrowObject();
		return client;
	}

	/**
	 * 归还一个连接对象到池子中
	 * @param ftpClient (归还的连接)
	 */
	public void returnObject(FTPClient ftpClient) {
		if (ftpClient != null) {
			pool.returnObject(ftpClient);
		}
	}
}

 

FtpClientUtils.java

package cn.itsub.code.utils.ftp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * FTPClient工具类,提供上传、下载、删除、创建多层目录等功能
 * @author Master.Xia
 */
public class FtpClientUtils {
	
	private static Logger logger = LoggerFactory.getLogger(FtpClientUtils.class);
	
	private FTPClientPool pool;
	
	public FtpClientUtils(FTPClientPool pool) {
		this.pool=pool;
	}
	
	public void setPool(FTPClientPool pool) {
		this.pool = pool;
	}

	/**
	 * 在FTP的工作目录下创建多层目录
	 * @param path (路径分隔符使用"/",且以"/"开头,例如"/data/photo/2018")
	 * @return (耗时多少毫秒)
	 * @throws Exception (异常)
	 */
	public int mkdirs(String path) throws Exception {
		FTPClient client = null;
		String workDirectory = null;
		try {
			client = pool.borrowObject();
			long start = System.currentTimeMillis();
			checkPath(path);
			workDirectory = client.printWorkingDirectory();
			File f = new File(workDirectory+path);
			List<String> names = new LinkedList<String>();
			while(f!=null&&f.toString().length()>0) {
				names.add(0, f.toString().replaceAll("\\\\", "/"));
				f=f.getParentFile();
			}
			for(String name:names) {
				client.makeDirectory(name);
			}
			return (int) (System.currentTimeMillis()-start);
		} catch (Exception e) {
			throw e;
		}finally {
			if(client!=null) {
				client.changeWorkingDirectory(workDirectory);
				pool.returnObject(client);
			}
		}
		
	}

	/**
	 * 上传文件到FTP工作目录
	 * @param localFile (上传的文件)
	 * @param path (在工作目录中的路径,示例"/data/2018")
	 * @param filename (文件名,示例"default.jpg")
	 * @return (耗时多少毫秒)
	 * @throws Exception (异常)
	 */
	public int store(File localFile,String path,String filename) throws Exception {
		InputStream in = new FileInputStream(localFile);
		return store(in, path, filename);
	}
	/**
	 * 上传文件到FTP工作目录,path示例"/data/2018",filename示例"default.jpg"
	 * @param in (要上传的输入流)
	 * @param path (在工作目录中的路径,示例"/data/2018")
	 * @param filename (文件名,示例"default.jpg")
	 * @return (耗时多少毫秒)
	 * @throws Exception (异常)
	 */
	public int store(InputStream in,String path,String filename) throws Exception {
		FTPClient client = null;
		String workDirectory = null;
		try {
			client=pool.borrowObject();
			workDirectory = client.printWorkingDirectory();
			checkPath(path);
			long start = System.currentTimeMillis();
			synchronized (client) {
		        mkdirs(path);
		        client.changeWorkingDirectory(workDirectory+path);
		        client.setFileType(FTP.BINARY_FILE_TYPE);
		        client.storeFile(filename, in);
			}
			return (int) (System.currentTimeMillis()-start);
		} catch (IOException e) {
			throw e;
		}finally {
			if(client!=null) {
				client.changeWorkingDirectory(workDirectory);
				pool.returnObject(client);
			}
		}
		
	}
	/**
	 * 删除FTP工作目录中的指定文件
	 * @param pathname (文件路径,示例"/data/2018/default.jpg")
	 * @return (删除成功返回true,删除失败返回false)
	 * @throws Exception (IO异常)
	 */
	public boolean delete(String pathname) throws Exception {
		FTPClient client = null;
	    try {
	    	client=pool.borrowObject();
			return client.deleteFile(pathname);
		} catch(Exception e){
			logger.error("删除文件失败",e);
			throw e;
		}finally {
			if(client!=null)pool.returnObject(client);
		}
	}
	/**
	 * 从FTP工作目录下载remote文件
	 * @param remote (FTP文件路径,示例"/data/2018/default.jpg")
	 * @param local (保存到本地的位置)
	 * @throws Exception (异常)
	 * @return (耗时多少毫秒)
	 */
	public int retrieve(String remote,File local) throws Exception{
		return retrieve(remote, new FileOutputStream(local));
	}
	/**
     * 从FTP工作目录下载remote文件
     * @param remote  (文件路径,示例"/data/2018/default.jpg")
     * @param out (输出流)
     * @throws Exception (异常)
     * @return (耗时多少毫秒)
     */
	public int retrieve(String remote,OutputStream out) throws Exception  {
		InputStream in =null;
		FTPClient client = null;
	    try {
	    	client=pool.borrowObject();
	    	  long start =System.currentTimeMillis();
	    	  in=client.retrieveFileStream(remote);
	    	  if(in != null){
	    		  byte[] buffer = new byte[1024];
	    		  for(int len;(len=in.read(buffer))!=-1;) {
	    			  out.write(buffer,0,len);
	    		  }
	    		  return (int)(System.currentTimeMillis()-start);
	    	  }else{
	    		  throw new RuntimeException("FTP Client retrieve Faild.");
	    	  }
		}catch(Exception e){
			logger.error("获取ftp下载流异常",e);
			throw e;
		}finally{
			try { if (in!=null) {in.close();}} catch (Exception e2) { }
			try { if (out!=null) {out.close();}} catch (Exception e2) { }
			try { if(client!=null)pool.returnObject(client); } catch (Exception e2) { }
		}
	}
	
	private static void checkPath(String path) {
		if(path.contains("\\")) {
			throw new RuntimeException("'\\' is not allowed in the path,please use '/'");
		}
		if(!path.startsWith("/")) {
			throw new RuntimeException("Please start with '/'");
		}
		if(!path.endsWith("/")) {
			throw new RuntimeException("Don't end with '/'");
		}
	}
	
}

 

调用方法

//配置信息
FtpPoolConfig cfg = new FtpPoolConfig();
cfg.setHost("127.0.0.1");
cfg.setPort(21);
cfg.setUsername("demo");
cfg.setPassword("123123");
cfg.setPoolEvictInterval(30000);
FTPClientFactory factory = new FTPClientFactory(cfg);//对象工厂
FTPClientPool pool = new FTPClientPool(factory);//连接池对象
//创建工具对象
FtpClientUtils ftp = new FtpClientUtils(pool);


int t1=util.mkdirs( "/data/imgs"); //在FTP的工作目录下创建多层目录
InputStream in = new FileInputStream("D:/001.jpg"); //读取一个本地文件
int t2=util.store( in, "/data/imgs/", "main.jpg");//上传到FTP服务器
int t3=util.retrieve( "/data/imgs/main.jpg", new FileOutputStream("D:/002.jpg"));//从FTP服务器取回文件
util.delete("/data/imgs/2018/09/29/main.jpg"); //删除FTP服务器中的文件

System.out.println("目录耗时:"+t1);
System.out.println("上传耗时:"+t2);
System.out.println("下载耗时:"+t3);


//FTPClient c = pool.borrowObject();//从池子中借一个FTPClient对象
//pool.returnObject(c);//把对象归还给池子

使用工具对象就可以创建目录,上传文件,下载文件

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程大玩家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值