# ftp-starter **Repository Path**: Instinctb/ftp-starter ## Basic Information - **Project Name**: ftp-starter - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-17 - **Last Updated**: 2026-04-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Ftp连接池-springboot-starter ## 1.背景: 项目开发过程中,经常使用的ftp的工具类,为了减少ftp的创建连接和关闭连接,需要一个类似数据库连接池的ftp连接池 ## 2.项目依赖: ``` commons-net commons-net org.apache.commons commons-pool2 ``` 2.2 pool2的组成 - PooledObject(池化对象) - PooledObjectFactory(对象工厂) - ObjectPool (对象池) 对应为: - FTPClient(池化对象) - FTPClientFactory(对象工厂) - FTPClientPool(对象池) - ![image](https://upload-images.jianshu.io/upload_images/12696746-1185dffaff25de9d.png?imageMogr2/auto-orient/strip|imageView2/2/w/546/format/webp) ## 3.FTP配置类 ``` @Data @Component @PropertySource("classpath:ftp.properties") @ConfigurationProperties(prefix = "ftp") public class FtpConfigOptions extends GenericObjectPoolConfig { /** * 地址 */ private String host; /** * 端口号 */ private int port=21; /** * 用户名 */ private String username; /** * Miami */ private String password; /** * 方式 */ private int passiveMode = FTP.BINARY_FILE_TYPE; /** * 编码方式 */ private String encoding="UTF-8"; /** * 超时时间 */ private int clientTimeout=120000; /** * 缓冲区 */ private int bufferSize =1024; ``` ## 4.FTP连接工厂 在commons-pool2中有两种工厂:PooledObjectFactory 和KeyedPooledObjectFactory,我们使用前者 ``` public interface PooledObjectFactory { //创建对象 PooledObject makeObject(); //激活对象 void activateObject(PooledObject obj); //钝化对象 void passivateObject(PooledObject obj); //验证对象 boolean validateObject(PooledObject obj); //销毁对象 void destroyObject(PooledObject obj); } ``` ``` @Slf4j public class FtpClientFactory implements PooledObjectFactory { private FtpConfigOptions ftpProperties; public FtpClientFactory(FtpConfigOptions ftpProperties) { this.ftpProperties = ftpProperties; } /** * 创建client端 * @return * @throws Exception */ @Override public PooledObject makeObject() throws Exception { FTPClient ftpClient = new FTPClient(); ftpClient.setControlEncoding(ftpProperties.getEncoding()); ftpClient.setConnectTimeout(ftpProperties.getClientTimeout()); try { ftpClient.connect(ftpProperties.getHost(), ftpProperties.getPort()); int reply = ftpClient.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftpClient.disconnect(); log.warn("FTPServer refused connection"); return null; } boolean result = ftpClient.login(ftpProperties.getUsername(), ftpProperties.getPassword()); ftpClient.setFileType(ftpProperties.getPassiveMode()); if (!result) { log.warn("ftpClient login failed... username is {}", ftpProperties.getUsername()); } } catch (Exception e) { log.error("create ftp connection failed...{}", e); throw e; } return wrap(ftpClient); } /** * 包装成PooledObject * @param ftpClient * @return */ public PooledObject wrap(FTPClient ftpClient) { return new DefaultPooledObject(ftpClient); } /** * 销毁对象 * * @param pooledObject * @throws Exception */ @Override public void destroyObject(PooledObject pooledObject) throws Exception { try { if(pooledObject.getObject() != null && pooledObject.getObject().isConnected()) { pooledObject.getObject().logout(); } } catch (Exception e) { log.error("ftp client logout failed...{}", e); throw e; } finally { if(pooledObject.getObject() != null) { pooledObject.getObject().disconnect(); } } } /** * a验证对象是否正确 * @param pooledObject * @return */ @Override public boolean validateObject(PooledObject pooledObject) { try { pooledObject.getObject().sendNoOp(); } catch (Exception e) { log.error("Failed to validate client: {}"); } return false; } @Override public void activateObject(PooledObject pooledObject) throws Exception { } @Override public void passivateObject(PooledObject pooledObject) throws Exception { } ``` ## 5.FTP连接池 ``` public class FtpClientPool extends GenericObjectPool { private FtpClientFactory ftpClientFactory; private FtpConfigOptions ftpConfigOptions; public FtpClientPool(FtpClientFactory ftpClientFactory,FtpConfigOptions ftpConfigOptions) { super(ftpClientFactory,ftpConfigOptions); this.ftpClientFactory=ftpClientFactory; this.ftpConfigOptions=ftpConfigOptions; } ``` ## 6.FTP工具类 ``` public class FtpUtils { /** * FTP的连接池 */ public static FtpClientPool ftpClientPool; /** * FTPClient对象 */ public static FTPClient ftpClient; //@Autowired static方式可以采用setter方法 public FtpUtils(FtpClientPool ftpClientPool) { FtpUtils.ftpClientPool= ftpClientPool; } //private static FtpUtils ftpUtils; /* *//** * 初始化设置 * @return *//* @PostConstruct public boolean init() { ftpUtils = this; return true; }*/ /** * 获取连接对象 * @return * @throws Exception */ public static FTPClient getFTPClient() throws Exception { //初始化的时候从队列中取出一个连接 synchronized (ftpClientPool) { ftpClient = ftpClientPool.borrowObject(); } return ftpClient; } /** * 当前命令执行完成命令完成 * @throws IOException */ public void complete() throws IOException { ftpClient.completePendingCommand(); } /** * 当前线程任务处理完成,加入到队列的最后 * @return */ public void disconnect() throws Exception { ftpClientPool.returnObject(ftpClient); } /** * Description: 向FTP服务器上传文件 * * @Version1.0 * @param remoteFile * 上传到FTP服务器上的文件名 * @param input * 本地文件流 * @return 成功返回true,否则返回false */ public static boolean uploadFile(String remoteFile, InputStream input) { boolean result = false; try { getFTPClient(); ftpClient.enterLocalPassiveMode(); result = ftpClient.storeFile(remoteFile, input); input.close(); ftpClient.disconnect(); } catch (Exception e) { e.printStackTrace(); } return result; } /** * Description: 向FTP服务器上传文件 * * @Version1.0 * @param remoteFile * 上传到FTP服务器上的文件名 * @param localFile * 本地文件 * @return 成功返回true,否则返回false */ public static boolean uploadFile(String remoteFile, String localFile){ FileInputStream input = null; try { input = new FileInputStream(new File(localFile)); } catch (FileNotFoundException e) { e.printStackTrace(); } return uploadFile(remoteFile, input); } /** * 拷贝文件 * @param fromFile * @param toFile * @return * @throws Exception */ public boolean copyFile(String fromFile, String toFile) throws Exception { InputStream in=getFileInputStream(fromFile); getFTPClient(); boolean flag = ftpClient.storeFile(toFile, in); in.close(); return flag; } /** * 获取文件输入流 * @param fileName * @return * @throws IOException */ public static InputStream getFileInputStream(String fileName) throws Exception { ByteArrayOutputStream fos=new ByteArrayOutputStream(); getFTPClient(); ftpClient.retrieveFile(fileName, fos); ByteArrayInputStream in=new ByteArrayInputStream(fos.toByteArray()); fos.close(); return in; } /** * Description: 从FTP服务器下载文件 * * @Version1.0 * @return */ public static boolean downFile(String remoteFile, String localFile){ boolean result = false; try { getFTPClient(); OutputStream os = new FileOutputStream(localFile); ftpClient.retrieveFile(remoteFile, os); ftpClient.logout(); ftpClient.disconnect(); result = true; } catch (Exception e) { e.printStackTrace(); } finally { try { } catch (Exception e) { e.printStackTrace(); } } return result; } /** * 从ftp中获取文件流 * @param filePath * @return * @throws Exception */ public static InputStream getInputStream(String filePath) throws Exception { getFTPClient(); InputStream inputStream = ftpClient.retrieveFileStream(filePath); return inputStream; } /** * ftp中文件重命名 * @param fromFile * @param toFile * @return * @throws Exception */ public boolean rename(String fromFile,String toFile) throws Exception { getFTPClient(); boolean result = ftpClient.rename(fromFile,toFile); return result; } /** * 获取ftp目录下的所有文件 * @param dir * @return */ public FTPFile[] getFiles(String dir) throws Exception { getFTPClient(); FTPFile[] files = new FTPFile[0]; try { files = ftpClient.listFiles(dir); }catch (Throwable thr){ thr.printStackTrace(); } return files; } /** * 获取ftp目录下的某种类型的文件 * @param dir * @param filter * @return */ public FTPFile[] getFiles(String dir, FTPFileFilter filter) throws Exception { getFTPClient(); FTPFile[] files = new FTPFile[0]; try { files = ftpClient.listFiles(dir, filter); }catch (Throwable thr){ thr.printStackTrace(); } return files; } /** * 创建文件夹 * @param remoteDir * @return 如果已经有这个文件夹返回false */ public boolean makeDirectory(String remoteDir) throws Exception { getFTPClient(); boolean result = false; try { result = ftpClient.makeDirectory(remoteDir); } catch (IOException e) { e.printStackTrace(); } return result; } public boolean mkdirs(String dir) throws Exception { boolean result = false; if (null == dir) { return result; } getFTPClient(); ftpClient.changeWorkingDirectory("/"); StringTokenizer dirs = new StringTokenizer(dir, "/"); String temp = null; while (dirs.hasMoreElements()) { temp = dirs.nextElement().toString(); //创建目录 ftpClient.makeDirectory(temp); //进入目录 ftpClient.changeWorkingDirectory(temp); result = true; } ftpClient.changeWorkingDirectory("/"); return result; } ``` ## 7.使用 ## 8.参考资料 https://www.jianshu.com/p/292d376179b1?utm_source=oschina-app