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();
}
}