当前位置: 首页 > news >正文

封装FTPSClient连接ftps服务器

主要是connect方法中一些set方法操作是必要的
支持try with resource

@Slf4j
public class FtpsClient implements AutoCloseable {private final String host;private final int port;private final String username;private final String password;private final int connectTimeout;private FTPSClient ftpsClient;public FtpsClient(String host, int port, String username, String password) {this(host, port, username, password, 10000);}public FtpsClient(String host, int port, String username, String password, int connectTimeout) {this.host = host;this.port = port;this.username = username;this.password = password;this.connectTimeout = connectTimeout;}/*** 连接到FTPS服务器*/public boolean connect() {if (isConnected()) {return true;}try {log.debug("[FtpsClient] Initializing FTPS client");ftpsClient = new FTPSClient();ftpsClient.setTrustManager(TrustManagerUtils.getAcceptAllTrustManager());ftpsClient.setEndpointCheckingEnabled(false);ftpsClient.setConnectTimeout(connectTimeout);ftpsClient.setDataTimeout(Duration.ofSeconds(30));FTPClientConfig config = new FTPClientConfig();ftpsClient.configure(config);ftpsClient.addProtocolCommandListener(new PrintCommandListener(// 打印ftp服务器日志,重定向到Slf4jnew PrintWriter(new LogWriter(log))));ftpsClient.setControlEncoding("UTF-8");log.debug("[FtpsClient] Connecting to {}:{}", host, port);ftpsClient.connect(host, port);int reply = ftpsClient.getReplyCode();if (!FTPReply.isPositiveCompletion(reply)) {throw new IOException("FTPS server refused connection: " + reply);}if (!ftpsClient.login(username, password)) {throw new IOException("Login failed for user: " + username);}ftpsClient.enterLocalPassiveMode();ftpsClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);// 数据通道加密ftpsClient.execPROT("P");ftpsClient.setFileType(FTP.BINARY_FILE_TYPE);// 1MB bufferftpsClient.setBufferSize(1024 * 1024);log.info("[FtpsClient] Connected to FTPS server: {}:{}", host, port);return true;} catch (Exception e) {log.error("[FtpsClient] Connection failed to {}:{} - {}", host, port, e.getMessage());disconnectSilently();throw new RuntimeException("FTPS connection failed: " + e.getMessage(), e);}}/*** 返回底层FTPS客户端实例*/public FTPSClient operation() {connectedCheck();return ftpsClient;}/*** 上传文件到FTPS服务器** @param localFilePath 本地文件路径* @param remoteDirectory 远程目录路径* @return 是否上传成功*/public boolean uploadFile(String localFilePath, String remoteDirectory) {connectedCheck();File localFile = new File(localFilePath);try (InputStream is = Files.newInputStream(Paths.get(localFilePath))) {createRemoteDirectory(remoteDirectory);String remotePath = remoteDirectory + "/" + localFile.getName();log.debug("[FtpsClient] Uploading file: {}", localFilePath);if (!ftpsClient.storeFile(remotePath, is)) {throw new IOException("Upload failed. Server reply: " + ftpsClient.getReplyString());}verifyUploadSuccess(localFile, remotePath);log.info("[FtpsClient] File uploaded successfully: {}", remotePath);return true;} catch (Exception e) {log.error("[FtpsClient] Upload failed: {}", e.getMessage());throw new RuntimeException("FTPS upload failed: " + e.getMessage(), e);}}/*** 从FTPS服务器下载文件** @param remoteFilePath 远程文件路径* @param localFilePath 本地存储文件路径* @return 是否下载成功*/public boolean retrieveFile(String remoteFilePath, String localFilePath) {connectedCheck();try (OutputStream os = Files.newOutputStream(Paths.get(localFilePath))) {log.debug("[FtpsClient] Downloading file: {}", remoteFilePath);if (!ftpsClient.retrieveFile(remoteFilePath, os)) {throw new IOException("Download failed. Server reply: " + ftpsClient.getReplyString());}File localFile = new File(localFilePath);if (!localFile.exists() || localFile.length() == 0) {throw new IOException("Local file not created or empty");}log.info("[FtpsClient] File downloaded successfully: {}", localFilePath);return true;} catch (Exception e) {log.error("[FtpsClient] Download failed: {}", e.getMessage());throw new RuntimeException("FTPS download failed: " + e.getMessage(), e);}}/*** 递归创建远程目录*/public boolean createRemoteDirectory(String path) throws IOException {connectedCheck();if (path == null || path.isEmpty()) {return true;}String[] dirs = path.split("/");StringBuilder currentPath = new StringBuilder();for (String dir : dirs) {if (dir.isEmpty()) {continue;}currentPath.append("/").append(dir);String dirPath = currentPath.toString();if (!ftpsClient.changeWorkingDirectory(dirPath)) {if (ftpsClient.makeDirectory(dirPath)) {log.debug("[FtpsClient] Created directory: {}", dirPath);} else {throw new IOException("Failed to create directory: " + dirPath);}ftpsClient.changeWorkingDirectory(dirPath);}}return true;}/*** 验证上传文件完整性** @param localFile 本地文件* @param remotePath 远程路径* @throws IOException 抛出异常*/private void verifyUploadSuccess(File localFile, String remotePath) throws IOException {long localSize = localFile.length();long remoteSize = ftpsClient.listFiles(remotePath)[0].getSize();if (localSize != remoteSize) {throw new IOException(String.format("Size mismatch! Local: %d bytes, Remote: %d bytes",localSize, remoteSize));}log.debug("[FtpsClient] File verification passed: {} bytes", remoteSize);}/*** 连接状态检查*/private void connectedCheck() {if (!isConnected()) {throw new IllegalStateException("FTPS connection not established");}}/*** 判断连接状态* @return boolean*/public boolean isConnected() {return ftpsClient != null && ftpsClient.isConnected();}/*** 静默断开连接*/private void disconnectSilently() {try {close();} catch (Exception e) {log.debug("[FtpsClient] Error during disconnect: {}", e.getMessage());}}@Overridepublic void close() {if (ftpsClient != null) {try {if (ftpsClient.isConnected()) {ftpsClient.logout();}} catch (IOException e) {log.debug("[FtpsClient] Logout failed: {}", e.getMessage());} finally {try {ftpsClient.disconnect();} catch (IOException e) {log.debug("[FtpsClient] Disconnect failed: {}", e.getMessage());}}}}/*** 日志重定向辅助类* @author changxin.man* @date 2025/08/21*/private static class LogWriter extends Writer {private final org.slf4j.Logger logger;LogWriter(org.slf4j.Logger logger) {this.logger = logger;}@Overridepublic void write(char[] cbuf, int off, int len) {if (logger.isDebugEnabled()) {String message = new String(cbuf, off, len).trim();if (!message.isEmpty()) {logger.debug("[FTPS] {}", message);}}}@Overridepublic void flush() {}@Overridepublic void close() {}}
}
http://www.dtcms.com/a/343015.html

相关文章:

  • 一个成熟的运维及售后岗位应掌握的知识体系详解
  • Linux动态库制作和使用
  • Manus AI 与多语言手写识别:技术、应用与未来
  • Nginx + Vue/React 前端 + API:防止路径混淆漏洞与跨域问题实战分享
  • [Mysql数据库] Mysql安全知识
  • Oracle ADG 切换方式详解:Switchover 与 Failover 操作指南
  • 〖领码方案〗前端 PageData 完整解决方案 第四版
  • 深度解析Structured Outputs:让AI输出严格遵循JSON Schema的结构化响应
  • 【日常学习】2025-8-21 了解些测试名词
  • 【GPT入门】第52课 openwebui安装与使用
  • Zynq中级开发七项必修课-第三课:S_AXI_GP0 主动访问 PS 地址空间
  • 通信算法之317:基于Xilinx FPGA平台的符号同步算法(接收序列与本地序列互相关-不共轭乘)
  • ODDR实现多bit单边沿采样数据转为多bit双沿采样数据
  • 前端-Vue笔记(核心语法)
  • linux内核 - 内存分配机制介绍
  • MySQL 8.4.6 LTS 安装教程 windows
  • 如何在mac玩windows游戏?3个工具推荐,不用换电脑!
  • MiniGPT-4
  • 在Excel和WPS表格中合并多个单元格这样最快
  • 第14章 结构和其他数据形式
  • 数据分类分级的关键难点以及应对之道
  • Go1.25的源码分析-src/runtime/runtime1.go(GMP)g
  • U盘安装 CentOS Stream 10 实战复盘:三大常见问题与解决方法
  • 通义千问VL-Plus:当AI“看懂”屏幕,软件测试的OCR时代正式终结!
  • Java 项目中 MySQL 数据向 Redis 迁移的技术实践与深度剖析
  • JVM 性能监控工具全解析:从命令行到可视化全方位指南
  • 图像形态学:膨胀、腐蚀和边缘检测与绘制
  • Java后端面试场景题大全:2025年高频考点深度解析
  • 大模型部署
  • 造成云手机闪退的原因有哪些?