在Java中实现SFTP协议文件传输的两种解决方案
程序员文章站
2024-03-24 15:22:10
...
在Java中实现SFTP协议文件传输的两种解决方案
这篇博文来聊聊在Java中实现SFTP协议文件传输的两种解决方案
1.1 背景
我们知道,XFTP 是一款非常流行的 FTP 文件传输工具。
其中 XFTP 目前支持两种文件传输协议
- 一种是FTP
- 另外一种是SFTP
如图所示:
当然除此之外还有一种不太常用的FTPS
那么这三种协议有哪些区别呢?
文件传输协议类型 | 描述 |
---|---|
FTP | 基础的文件传输 |
FTPS | 基于TLS 加密 |
SFTP | 基于SSH 加密 |
有时候我们可能会有需求,在我们的项目中使用FTP 文件传输功能。
那么在Java中有哪些解决方案呢?
1.2 关于 FTP /FTPS
Apache Commons Net™库实现了许多基本Internet协议的客户端。
支持的协议如下所示:
- FTP/FTPS
- FTP over HTTP (experimental)
- NNTP
- SMTP(S)
- POP3(S)
- IMAP(S)
- Telnet
- TFTP
- Finger
- Whois
- rexec/rcmd/rlogin
- Time (rdate) and Daytime
- Echo
- Discard
- NTP/SNTP
其中这个类库中有如下三个类:
- org.apache.commons.net.tftp.TFTPClient
支持不需要账号密码访问的FTP 协议文件传输,不支持带验证的FTP文件传输- org.apache.commons.net.ftp.FTPClient
支持FTP,不支持FTPS和SFTP- org.apache.commons.net.ftp.FTPSClient
支持FTPS,不支持SFTP
前面两种方式这里不做过多讨论,我们重点看下SFTP 协议文件传输的解决方案。
1.3 关于SFTP
关于在Java中实现SFTP协议文件传输有两个库可供使用。
- 使用 JSch 库
- 使用sshj 库
为了便于测试,我这里将账号密码等信息配置成静态工具类
代码如下所示:
/**
* @author qing-feng.zhao
*/
public class MyServerInfoConstant {
/**
* FTP IP 地址
*
*/
public static final String REMOTE_SERVER_IP="127.0.0.1";
/**
* Sftp账号
*/
public static final String USER_NAME="root";
/**
* Sftp密码
*/
public static final String PASS_WORD="toor";
/**
* 测试远程服务器的文件路径
*/
public static final String SRC_FILE_PATH="/opt/app/remote.txt";
/**
* 本地保存文件路径
*/
public static final String TARGET_FILE_PATH="C:/test/local.txt";
/**
* 禁用构造方法
*/
private MyServerInfoConstant(){}
}
请自行修改IP 账号和密码为自己FTP 服务器的账号和密码。
解决方案一:使用 JSch 库
调用代码如下:
import com.xingyun.constant.MyServerInfoConstant;
import com.xingyun.utils.SmartSftpUtils;
/**
* http://www.jcraft.com/jsch/
* @author qing-feng.zhao
*/
public class SmartSftpUtilsTest {
public static void main(String[] args) {
//FTP IP
String remoteServerIp= MyServerInfoConstant.REMOTE_SERVER_IP;
//默认是22端口
//Sftp账号
String username=MyServerInfoConstant.USER_NAME;
//Sftp密码
String password=MyServerInfoConstant.PASS_WORD;
//远程服务器地址
String remoteFilePath=MyServerInfoConstant.SRC_FILE_PATH;
//本地保存文件路径
String localFilePath=MyServerInfoConstant.TARGET_FILE_PATH;
//调用工具类下载文件
SmartSftpUtils.downloadFileBySftp(remoteServerIp,username,password,remoteFilePath,localFilePath);
}
}
工具类配置如下:
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
/**
* @sees http://www.jcraft.com/jsch/
* @author qing-fegn.zhao
*/
@Slf4j
public final class SmartSftpUtils {
/**
*
* @param remoteServerIp
* @param username
* @param password
* @param remoteFilePath
* @param localFilePath
*/
public static void downloadFileBySftp(String remoteServerIp,
String username,
String password,
String remoteFilePath,
String localFilePath){
JSch jsch = new JSch();
try {
Session session = jsch.getSession(username, remoteServerIp, 22);
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword(password);
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
ChannelSftp sftpChannel = (ChannelSftp) channel;
sftpChannel.get(remoteFilePath, localFilePath);
sftpChannel.exit();
session.disconnect();
} catch (JSchException e) {
//To change body of catch statement use File | Settings | File Templates.
log.error(e.getMessage(),e);
} catch (SftpException e) {
log.error(e.getMessage(),e);
}
}
/**
* 禁用构造方法
*/
private SmartSftpUtils(){}
}
解决方案二:使用sshj 库
这个类库更加强大,除了基础的SFTP协议文件传输,还支持 Shell 下的各种常用命令,比如创建文件夹,列出文件目录等。
调用方法如下:
import com.xingyun.constant.MyServerInfoConstant;
import com.xingyun.utils.SmartSshUtils;
/**
* @author
*/
public class SmartSshUtilsTest {
public static void main(String[] args) {
String hostName= MyServerInfoConstant.REMOTE_SERVER_IP;
String username=MyServerInfoConstant.USER_NAME;
String password=MyServerInfoConstant.PASS_WORD;
String srcFilePath=MyServerInfoConstant.SRC_FILE_PATH;
String targetFilePath=MyServerInfoConstant.TARGET_FILE_PATH;
SmartSshUtils.downLoadFileBySsh(hostName,username,password,srcFilePath,targetFilePath);
}
}
sshJ工具类:
import lombok.extern.slf4j.Slf4j;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import java.io.IOException;
/**
* https://github.com/hierynomus/sshj
* @Sees https://*.com/questions/14617/how-to-retrieve-a-file-from-a-server-via-sftp
* @author qing-feng.zhao
*/
@Slf4j
public final class SmartSshUtils {
public static void downLoadFileBySsh(String hostName,
String username,
String password,
String srcFilePath,
String targetFilePath
) {
SSHClient ssh = new SSHClient();
SFTPClient sftpClient = null;
try {
//ssh.loadKnownHosts(); to skip host verification
ssh.addHostKeyVerifier(new PromiscuousVerifier());
ssh.connect(hostName);
ssh.authPassword(username, password);
sftpClient = ssh.newSFTPClient();
sftpClient.get(srcFilePath, targetFilePath);
//create a folder
sftpClient.mkdir("/opt/app/testFolder");
//sftpClient.mkdirs("");创建多级文件夹
//sftpClient.rmdir("");重命名文件夹
//sftpClient.ls(""); //列出当前目录
} catch (IOException e) {
log.error(e.getMessage(), e);
} finally {
if (null != sftpClient) {
try {
sftpClient.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
try {
ssh.disconnect();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
/**
* 静态工具类应该禁用构造方法
*/
private SmartSshUtils(){}
}
贴上完整的pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>SmartFtpSample</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<!-- 设置当前项目源码使用字符编码为UTF-8 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 设置当前项目所需要的JDK版本 Open JDK下载地址:https://jdk.java.net/ -->
<java.version>1.8</java.version>
<!-- 设置当前项目编译所需要的JDK版本 Open JDK下载地址:https://jdk.java.net/ -->
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<!-- 设置maven编译插件版本,可通过下面网址查看最新的版本-->
<!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-compiler-plugin -->
<maven.compiler.plugin.version>3.5.1</maven.compiler.plugin.version>
<!-- 项目所使用第三方依赖jar包的版本,建议以后都使用这种方式,方便今后维护和升级 -->
<lombok.version>1.18.10</lombok.version>
<commons.net.version>3.6</commons.net.version>
<spring.boot.version>2.1.6.RELEASE</spring.boot.version>
<jsch.version>0.1.55</jsch.version>
<sshj.version>0.27.0</sshj.version>
</properties>
<dependencies>
<!--added lombok support -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!--added logback as log lib -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>${spring.boot.version}</version>
<scope>compile</scope>
</dependency>
<!-- added Ftp and FTPS support -->
<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>${commons.net.version}</version>
</dependency>
<!-- added XFtp support -->
<!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>${jsch.version}</version>
</dependency>
<!-- added SFTP and Shell command support -->
<dependency>
<groupId>com.hierynomus</groupId>
<artifactId>sshj</artifactId>
<version>${sshj.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!--该插件限定Maven打包时所使用的版本,避免出现版本不匹配问题-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
这里只贴出部分,关于更多其他解决方案的探讨见我的Github.
上一篇: Tensorflow 模型转 tflite ,在安卓端使用
下一篇: hanoi汉诺塔问题的真谛