使用Java通过SFTP管理远程Linux服务器文件
基于JSch实现安全文件传输操作
在分布式系统开发中,经常需要与远程Linux服务器进行安全的文件交互。SFTP(SSH File Transfer Protocol)基于SSH协议提供加密的数据传输,是替代传统FTP的安全选择。本文介绍如何使用Java结合JSch库完成常见的远程文件操作,包括目录浏览、文件上传下载、删除以及以字节数组形式获取文件内容。
Maven依赖配置
项目需引入JSch用于SFTP通信,同时使用Apache Commons IO简化流处理:
<properties>
<jsch.version>0.1.55</jsch.version>
<commons-io.version>2.16.1</commons-io.version>
</properties>
<dependencies>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>${jsch.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
</dependencies>
SFTP客户端工具类实现
封装一个可复用的SFTP工具类,支持密码和私钥两种认证方式,并提供常用文件操作接口。
import com.jcraft.jsch.*;
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.util.Properties;
import java.util.Vector;
public class SecureFileTransferClient {
private ChannelSftp channel;
private Session sshSession;
private final String host;
private final int port;
private final String username;
private final String password;
private final String privateKeyPath;
// 密码认证构造函数
public SecureFileTransferClient(String username, String password, String host, int port) {
this(username, host, port, password, null);
}
// 私钥认证构造函数
public SecureFileTransferClient(String username, String host, int port, String privateKeyPath) {
this(username, host, port, null, privateKeyPath);
}
private SecureFileTransferClient(String username, String host, int port, String password, String privateKeyPath) {
this.username = username;
this.host = host;
this.port = port;
this.password = password;
this.privateKeyPath = privateKeyPath;
}
/**
* 建立SFTP连接
*/
public void connect() throws JSchException {
JSch jsch = new JSch();
if (privateKeyPath != null) {
jsch.addIdentity(privateKeyPath);
}
sshSession = jsch.getSession(username, host, port);
if (password != null) {
sshSession.setPassword(password);
}
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
sshSession.setConfig(config);
sshSession.connect();
channel = (ChannelSftp) sshSession.openChannel("sftp");
channel.connect();
}
/**
* 断开连接
*/
public void disconnect() {
if (channel != null && channel.isConnected()) {
channel.disconnect();
}
if (sshSession != null && sshSession.isConnected()) {
sshSession.disconnect();
}
}
/**
* 获取指定路径下的文件列表
*/
public Vector<LsEntry> listDirectory(String path) throws SftpException {
return channel.ls(path);
}
/**
* 删除远程文件
*/
public void removeFile(String remoteDir, String filename) throws SftpException {
channel.cd(remoteDir);
channel.rm(filename);
}
/**
* 上传输入流为远程文件,自动创建缺失目录
*/
public void uploadStream(String basePath, String targetDir, String remoteName, InputStream input)
throws SftpException {
try {
channel.cd(basePath);
ensureRemoteDirectoryExists(targetDir);
channel.put(input, remoteName);
} catch (SftpException e) {
throw new SftpException(e.id, "Upload failed: " + e.getMessage());
}
}
private void ensureRemoteDirectoryExists(String dirPath) throws SftpException {
String[] segments = dirPath.split("/");
StringBuilder currentPath = new StringBuilder();
for (String segment : segments) {
if (segment.isEmpty()) continue;
currentPath.append("/").append(segment);
try {
channel.cd(currentPath.toString());
} catch (SftpException ex) {
channel.mkdir(currentPath.toString());
channel.cd(currentPath.toString());
}
}
}
/**
* 下载文件到本地磁盘
*/
public void downloadToFile(String remoteDir, String filename, String localPath)
throws SftpException, FileNotFoundException {
if (remoteDir != null && !remoteDir.trim().isEmpty()) {
channel.cd(remoteDir);
}
channel.get(filename, localPath);
}
/**
* 下载文件并返回字节数组
*/
public byte[] downloadAsBytes(String remoteDir, String filename) throws IOException, SftpException {
if (remoteDir != null && !remoteDir.trim().isEmpty()) {
channel.cd(remoteDir);
}
try (InputStream inputStream = channel.get(filename)) {
return IOUtils.toByteArray(inputStream);
}
}
// 使用示例
public static void main(String[] args) {
SecureFileTransferClient client = new SecureFileTransferClient(
"yourUsername", "yourPassword", "192.168.1.100", 22);
try {
client.connect();
// 1. 列出/home/yourUsername目录内容
Vector<LsEntry> files = client.listDirectory("/home/yourUsername");
for (LsEntry entry : files) {
System.out.println("File: " + entry.getFilename());
}
// 2. 删除 test.txt 文件
client.removeFile("/home/yourUsername", "test.txt");
// 3. 上传本地文件
File source = new File("C:\\local\\data.txt");
try (FileInputStream fis = new FileInputStream(source)) {
client.uploadStream("/home/yourUsername", "uploads/temp", "uploaded.txt", fis);
}
// 4. 下载文件到本地
client.downloadToFile("/home/yourUsername/uploads", "uploaded.txt", "C:\\local\\downloaded.txt");
// 5. 以字节数组形式获取文件
byte[] data = client.downloadAsBytes("/home/yourUsername", "report.log");
System.out.println("Downloaded " + data.length + " bytes.");
} catch (Exception e) {
e.printStackTrace();
} finally {
client.disconnect();
}
}
}