Ftp连接池
maven引入,主要引入ftp的包和连接池的包 其他默认使用spring的包。
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
FTPConfiguration
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PreDestroy;
@Slf4j
@Configuration
@ConditionalOnClass({GenericObjectPool.class, FTPClient.class})
@EnableConfigurationProperties(FTPConfiguration.FtpConfigProperties.class)
public class FTPConfiguration {
private ObjectPool<FTPClient> pool;
public FTPConfiguration(FtpConfigProperties props) {
// 默认最大连接数与最大空闲连接数都为8,最小空闲连接数为0
// 其他未设置属性使用默认值,可根据需要添加相关配置
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
poolConfig.setTestWhileIdle(true);
poolConfig.setMinEvictableIdleTimeMillis(60000);
poolConfig.setSoftMinEvictableIdleTimeMillis(50000);
poolConfig.setTimeBetweenEvictionRunsMillis(30000);
pool = new GenericObjectPool<>(new FtpClientPooledObjectFactory(props), poolConfig);
preLoadingFtpClient(props.getInitialSize(), poolConfig.getMaxIdle());
// 初始化ftp工具类中的ftpClientPool
FtpUtils.init(pool);
}
/**
* 预先加载FTPClient连接到对象池中
* @param initialSize 初始化连接数
* @param maxIdle 最大空闲连接数
*/
private void preLoadingFtpClient(Integer initialSize, int maxIdle) {
if (initialSize == null || initialSize <= 0) {
return;
}
int size = Math.min(initialSize.intValue(), maxIdle);
for (int i = 0; i < size; i++) {
try {
pool.addObject();
} catch (Exception e) {
log.error("preLoadingFtpClient error...", e);
}
}
}
@PreDestroy
public void destroy() {
if (pool != null) {
pool.close();
log.info("销毁ftpClientPool...");
}
}
/**
* Ftp配置属性类,建立ftpClient时使用
*/
@Data
@ConfigurationProperties(prefix = "ftp")
static class FtpConfigProperties {
private String host;
private int port;
private String username;
private String password;
private int bufferSize = 8096;
private String encoding;
/**
* 初始化连接数
*/
private Integer initialSize = 0;
}
/**
* FtpClient对象工厂类
*/
static class FtpClientPooledObjectFactory implements PooledObjectFactory<FTPClient> {
private FtpConfigProperties props;
public FtpClientPooledObjectFactory(FtpConfigProperties props) {
this.props = props;
}
@Override
public PooledObject<FTPClient> makeObject() throws Exception {
FTPClient ftpClient = new FTPClient();
try {
ftpClient.connect(props.getHost(), props.getPort());
ftpClient.login(props.getUsername(), props.getPassword());
log.debug("连接FTP服务器返回码{}", ftpClient.getReplyCode());
ftpClient.setBufferSize(props.getBufferSize());
//ftpClient.setControlEncoding(props.getEncoding());
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
// ftpClient.enterLocalPassiveMode();
return new DefaultPooledObject<>(ftpClient);
} catch (Exception e) {
log.error("建立FTP连接失败", e);
if (ftpClient.isAvailable()) {
ftpClient.disconnect();
}
throw new Exception("建立FTP连接失败", e);
}
}
@Override
public void destroyObject(PooledObject<FTPClient> p) throws Exception {
FTPClient ftpClient = getObject(p);
if (ftpClient != null && ftpClient.isConnected()) {
ftpClient.disconnect();
}
}
@Override
public boolean validateObject(PooledObject<FTPClient> p) {
FTPClient ftpClient = getObject(p);
if (ftpClient == null || !ftpClient.isConnected()) {
return false;
}
try {
ftpClient.changeWorkingDirectory("/");
return true;
} catch (Exception e) {
log.error("验证FTP连接失败::{}", e);
return false;
}
}
@Override
public void activateObject(PooledObject<FTPClient> p) throws Exception {
}
@Override
public void passivateObject(PooledObject<FTPClient> p) throws Exception {
}
private FTPClient getObject(PooledObject<FTPClient> p) {
if (p == null || p.getObject() == null) {
return null;
}
return p.getObject();
}
}
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.pool2.ObjectPool;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.io.*;
@Slf4j
@Component
public class FtpUtils {
/**
* ftpClient连接池初始化标志
*/
private static volatile boolean hasInit = false;
/**
* ftpClient连接池
*/
private static ObjectPool<FTPClient> ftpClientPool;
private static String encoding;
@Value("${ftp.encoding}")
public void setEncoding(String encoding) {
FtpUtils.encoding = encoding;
}
public static void init(ObjectPool<FTPClient> ftpClientPool) {
if (!hasInit) {
synchronized (FtpUtils.class) {
if (!hasInit) {
FtpUtils.ftpClientPool = ftpClientPool;
hasInit = true;
}
}
}
}
private static FTPClient getFtpClient() {
checkFtpClientPoolAvailable();
FTPClient ftpClient = null;
Exception ex = null;
for (int i = 0; i < 3; i++) {
try {
ftpClient = ftpClientPool.borrowObject();
ftpClient.changeWorkingDirectory("/");
break;
} catch (Exception e) {
ex = e;
}
}
if (ftpClient == null) {
throw new RuntimeException("Could not get a ftpClient from the pool", ex);
}
return ftpClient;
}
public static String[] retrieveFTPFiles(String remotePath) throws IOException {
FTPClient ftpClient = getFtpClient();
try {
ftpClient.setControlEncoding(encoding);
ftpClient.changeWorkingDirectory(remotePath);
return ftpClient.listNames();
} finally {
releaseFtpClient(ftpClient);
}
}
public static FTPFile[] getFTPFiles() throws IOException {
FTPClient ftpClient = getFtpClient();
try {
return ftpClient.listFiles();
} finally {
releaseFtpClient(ftpClient);
}
}
public static void deleteFTPFiles(String path,String remotePath){
FTPClient ftpClient = getFtpClient();
try {
ftpClient.changeWorkingDirectory(path);
ftpClient.deleteFile(new String(remotePath.getBytes(encoding),"ISO-8859-1"));
} catch (IOException e) {
e.printStackTrace();
} finally {
releaseFtpClient(ftpClient);
}
}
public static void deleteFTPFiles(String remotePath,FTPClient ftpClient){
try {
ftpClient.deleteFile(new String(remotePath.getBytes(encoding),"ISO-8859-1"));
} catch (IOException e) {
e.printStackTrace();
}
}
private static void releaseFtpClient(FTPClient ftpClient) {
if (ftpClient == null) {
return;
}
try {
ftpClientPool.returnObject(ftpClient);
} catch (Exception e) {
log.error("Could not return the ftpClient to the pool", e);
// destoryFtpClient
if (ftpClient.isAvailable()) {
try {
ftpClient.disconnect();
} catch (IOException io) {
}
}
}
}
public static byte[] getFileBytesByName(String ftpPath, String fileName) {
// 登录
FTPClient ftpClient = getFtpClient();
//创建byte数组输出流
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
try {
ftpClient.changeWorkingDirectory(ftpPath);
InputStream is = ftpClient.retrieveFileStream(new String(fileName.getBytes(encoding),"ISO-8859-1"));
byte[] buffer = new byte[1024 * 1024 * 4];
int len = -1;
while ((len = is.read(buffer, 0, 1024 * 1024 * 4)) != -1) {
byteStream.write(buffer, 0, len);
}
is.close();
ftpClient.completePendingCommand();
}catch (Exception e){
log.error(e.getMessage(), e);
}finally {
releaseFtpClient(ftpClient);
}
return byteStream.toByteArray();
}
public static void upload(String path,File f){
FTPClient ftp = getFtpClient();
try {
ftp.changeWorkingDirectory(path);
ftp.setFileType(FTP.BINARY_FILE_TYPE);
InputStream input = new FileInputStream(f);
ftp.storeFile(new String(f.getName().getBytes(encoding),"ISO-8859-1"),input);
input.close();
} catch (FileNotFoundException fileNotFoundException) {
fileNotFoundException.printStackTrace();
} catch (IOException ioException) {
ioException.printStackTrace();
}finally {
releaseFtpClient(ftp);
}
}
public static void downloadFiles(String ftpPath, String savePath) {
FTPClient ftpClient = getFtpClient();
try {
// 判断是否存在该目录
if (!ftpClient.changeWorkingDirectory(ftpPath)) {
return;
}
ftpClient.enterLocalPassiveMode(); // 设置被动模式,开通一个端口来传输数据
String[] fs = ftpClient.listNames();
// 判断该目录下是否有文件
if (fs == null || fs.length == 0) {
return;
}
File files = new File(savePath);
if(!files.exists()){
files.mkdir();
}
for (String ff : fs) {
//String ftpName = new String(ff.getBytes("UTF-8"),encoding);
File file = new File(savePath + '/' + ff);
try (OutputStream os = new FileOutputStream(file)) {
ftpClient.retrieveFile(ff, os);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
releaseFtpClient(ftpClient);
}
}
private static void checkFtpClientPoolAvailable() {
Assert.state(hasInit, "FTP未启用或连接失败!");
}
}
配置文件
ftp.host=127.0.0.1
ftp.port=21
ftp.username=ftpTest
ftp.password=123456
#ftp服务编码,默认为GBK
ftp.encoding =GBK
#ftp 文件路径 默认为根目录
ftp.path = \\