首先引入maven依赖
commons-net
commons-net
3.6
org.apache.commons
commons-pool2
2.6.0
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 {
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 {
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 wrap(FTPClient ftpClient) {
return new DefaultPooledObject(ftpClient);
}
//销毁对象
@Override
public void destroyObject(PooledObject p) throws Exception {
FTPClient ftpClient = p.getObject();
ftpClient.logout();
super.destroyObject(p);
logger.info("destroyObject");
}
/**
* 验证对象
*/
@Override
public boolean validateObject(PooledObject 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 pool;
//ftp客户端工厂
private FTPClientFactory clientFactory;
/**
* 构造函数中 注入一个bean
* @param clientFactory
*/
public FTPClientPool(FTPClientFactory clientFactory) {
this.clientFactory = clientFactory;
pool = new GenericObjectPool(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 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 names = new LinkedList();
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);//把对象归还给池子
使用工具对象就可以创建目录,上传文件,下载文件