
ftp4j仅支持ftp/ftps协议,无法用于sftp连接;sftp基于ssh协议,必须选用jsch、apache mina sshd或spring integration sftp等专用库,并配置正确的ssh认证方式。
ftp4j仅支持ftp/ftps协议,无法用于sftp连接;sftp基于ssh协议,必须选用jsch、apache mina sshd或spring integration sftp等专用库,并配置正确的ssh认证方式。
it.sauronsoftware.ftp4j.FTPClient 是一个专为传统 FTP 协议设计的轻量级客户端,它完全不支持 SFTP(SSH File Transfer Protocol)。这是开发者常遇到的根本性误解:SFTP 与 FTPES(FTP over Explicit TLS)或 FTPS(FTP over Implicit TLS)在协议层面上毫无关系——SFTP 运行于 SSH 协议之上(默认端口 22),而 FTPES/FTPS 仍是 FTP 的加密扩展(默认端口 21)。因此,调用 setSecurity(FTPClient.SECURITY_FTPES) 或 setSecurity(FTPClient.SECURITY_FTPS) 试图连接 SFTP 服务器,必然失败,并抛出如 FTPIllegalReplyException 或 SSLException: Unsupported SSL message 等异常——因为目标服务器(SFTP)根本不会响应 FTP 命令或 TLS 握手请求。
✅ 正确方案:使用原生支持 SSH/SFTP 的 Java 库。推荐以下三种成熟选择:
-
JSch(最常用):轻量、稳定、社区广泛支持
import com.jcraft.jsch.*; JSch jsch = new JSch(); Session session = jsch.getSession("username", "host.example.com", 22); session.setPassword("password"); session.setConfig("StrictHostKeyChecking", "no"); // 生产环境应校验 known_hosts session.connect(); ChannelSftp sftp = (ChannelSftp) session.openChannel("sftp"); sftp.connect(); sftp.cd("/remote/path"); sftp.put("local-file.txt", "remote-file.txt"); sftp.disconnect(); session.disconnect();⚠️ 注意:JSch 已多年未更新(最后版本 0.1.55),若需 Java 17+ 支持或更强安全性,建议迁移到 Apache MINA SSHD。
-
Apache MINA SSHD(现代替代):主动维护、模块化、支持密钥轮换与高级认证
Alibabacloud Sdk Client Initialization For Java下载在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
<!-- Maven --> <dependency><groupid>org.apache.sshd</groupid><artifactid>sshd-sftp</artifactid><version>2.12.0</version></dependency>
SftpClient client = SftpClientBuilder.builder() .host("host.example.com") .port(22) .username("username") .password("password") .build(); try (client) { client.put(Paths.get("local.txt"), "/remote.txt"); } Spring Integration SFTP(企业级集成):适用于 Spring Boot 项目,天然支持异步、重试、事务与消息驱动流程。
? 总结关键原则:
- 协议不可混用:SFTP ≠ FTPS ≠ FTPES;选型前务必确认服务端实际启用的协议;
-
拒绝“打补丁式适配”:不要尝试用
ftp4j+ 自定义 socket 或反射绕过限制——这违背协议设计,注定不可靠; -
安全优先:禁用
StrictHostKeyChecking=no(开发调试除外),优先使用 SSH 密钥认证(jsch.addIdentity(privateKeyPath)),避免明文密码; -
连接生命周期管理:始终显式调用
disconnect()/close(),防止资源泄漏。
选择合适工具,理解协议本质,是构建健壮文件传输能力的第一步。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










