几周前,我评估了一些用于Java的SSH库。 对它们的主要要求是在远程计算机上进行文件传输和文件操作。 因此,它存在一个基于SSH,SSH文件传输协议(或SFTP)的网络协议。 因此,我需要一个支持SFTP的SSH库。
一项研究表明,它退出了许多用于Java的SSH库。 为了进行比较,我将库的数量减少到三个。 我选择JSch,SSHJ和Apache的Commons VFS,以获得更深入的了解。 它们都支持SFTP。 JSch似乎是Java的实际标准。 SSHJ是较新的库。 其目标是为SSH提供一个清晰的Java API。 它在后台使用Apache SSHD。 Commons VFS的目标是为虚拟文件系统提供清晰的API,SFTP是受支持的协议之一。 在后台,它将JSch用于SFTP协议。 这些库应满足以下要求:
- 通过密码进行客户端身份验证
- 通过公钥进行客户端身份验证
- 服务器认证
- 通过SFTP从本地主机上传文件
- 通过SFTP将文件下载到本地主机
- 远程主机上的文件操作,例如通过SFTP移动,删除,列出给定文件夹的所有子文件夹(在文件或文件夹等类型之后进行过滤)
- 执行普通的shell命令
让我们更深入地了解这三个库如何满足需求。
客户端认证
这三个库都支持两种必需的身份验证方法。 SSHJ具有最清晰的身份验证API( SSHClient.authUserPass(),SSHClient.authUserPublicKey() )。
SSHClient sshClient= new SSHClient();
sshClient.connect(host);
// only for public key authentication
sshClient.authPublickey("user", "location to private key file");
// only for password authentication
sshClient.authPassword("user", "password");
在Commons VFS中,身份验证配置取决于应使用哪种身份验证。 对于公共密钥身份验证,必须在FileSystemOption中设置私有密钥,并且用户名是连接URL的一部分。 对于密码验证,用户名和密码是连接URL的一部分。
StandardFileSystemManager fileSystemManager = new StandardFileSystemManager();
fileSystemManager.init();
// only for public key authentication
SftpFileSystemConfigBuilder sftpConfigBuilder = SftpFileSystemConfigBuilder.getInstance();
FileSystemOptions opts = new FileSystemOptions();
sftpConfigBuilder.setIdentities(opts, new File[]{privateKey.toFile()});
String connectionUrl = String.format("sftp://%s@%s", user, host);
// only for password authentication
String connectionUrl = String.format("sftp://%s:%s@%s", user, password, host);
// Connection set-up
FileObject remoteRootDirectory = fileSystemManager.resolveFile(connectionUrl, connectionOptions);
JSch中的认证配置类似于Commons VFS。 这取决于应使用哪种身份验证。 必须在JSch对象中配置用于公共密钥认证的私钥,并且必须在Session对象中设置用于密码认证的密码。 对于两者,当JSch对象获取Session对象时,将设置用户名。
JSch sshClient = new JSch();
// only for public key authentication
sshClient.addIdentity("location to private key file");
session = sshClient.getSession(user, host);
// only for password authentication
session.setPassword(password);
session.connect();
服务器认证
这三个库均支持服务器身份验证。 在SSHJ中,可以使用SSHClient.loadKnownHost启用服务器身份验证。 可以添加自己的known_host文件位置,也可以使用默认位置,该位置取决于使用平台。
SSHClient sshClient = new SSHClient();
sshClient.loadKnownHosts(); // or sshClient.loadKnownHosts(knownHosts.toFile());
sshClient.connect(host);
在Commons VFS中,服务器身份验证配置也是FileSystemOption的一部分,类似于公钥身份验证。 在那里,可以设置known_hosts文件的位置。
SftpFileSystemConfigBuilder sftpConfigBuilder = SftpFileSystemConfigBuilder.getInstance();
FileSystemOptions opts = new FileSystemOptions();
sftpConfigBuilder.setKnownHosts(opts, new File("location of the known_hosts file"));
在JSch中,存在两种配置服务器身份验证的可能性。 一种可能性是使用OpenSSHConfig (请参阅JSch示例以了解OpenSSHConfig )。 另一种可能性更容易。 可以直接在JSch对象中设置known_hosts文件的位置。
JSch sshClient = new JSch();
sshClient.setKnownHosts("location of known-hosts file");
通过SFTP上传/下载文件
这三个库均支持通过SFTP上传和下载文件。 SSHJ具有非常清晰的API用于这些操作。 SSHClient对象创建一个SFTPClient对象。 这个对象负责上传(SFTPClient。PUT)和下载(SFTPClient。 获得 )。
SSHClient sshClient = new SSHClient();
// ... connection
try (SFTPClient sftpClient = sshClient.newSFTPClient()) {
// download
sftpClient.get(remotePath, new FileSystemFile(local.toFile()));
// upload
sftpClient.put(new FileSystemFile(local.toFile()), remotePath);
}
在Commons VFS中,上传和下载文件被抽象为在文件系统上的操作。 因此,两者均由FileObject对象的copyFrom方法表示。 上传是参数】remotefile对象上的copyfrom操作和下载是在LOCALFILE一个的copyfrom操作。
StandardFileSystemManager fileSystemManager = new StandardFileSystemManager();
// ... configuration
remoteRootDirectory = fileSystemManager.resolveFile(connectionUrl, connectionOptions);
LocalFile localFileObject = (LocalFile) fileSystemManager.resolveFile(local.toUri().toString());
FileObject remoteFileObject = remoteRootDirectory.resolveFile(remotePath);
try {
// download
localFileObject.copyFrom(remoteFileObject, new AllFileSelector());
// upload
remoteFileObject.copyFrom(localFileObject, new AllFileSelector());
} finally {
localFileObject.close();
remoteFileObject.close();
}
JSch还支持SFTPClient。 在JSch中,它称为ChannelSFTP 。 它有两种下载( ChannelSFTP.get )和上载( ChannelSFTP.put )的方法。
// here: creation and configuration of session
ChannelSftp sftpChannel = null;
try {
sftpChannel = (ChannelSftp) session.openChannel("sftp");
sftpChannel.connect();
// download
InputStream inputStream = sftpChannel.get(remotePath);
Files.copy(inputStream, localPath);
// upload
OutputStream outputStream = sftpChannel.put(remotePath);
Files.copy(locaPathl, outputStream);
} catch (SftpException | JSchException ex) {
throw new IOException(ex);
} finally {
if (sftpChannel != null) {
sftpChannel.disconnect();
}
}
执行Shell命令
仅Commons VFS不支持执行普通Shell命令。 在SSHJ中,它是两层的。 SshClient启动一个新的Session对象。 该对象执行shell命令。 这是非常直观的。
// creation and configuration of sshClient
try (Session session = sshClient.startSession()) {
session.exec("ls");
}
在Jsch中, ChannelExec负责通过SSH执行Shell命令。 首先,在通道中设置命令,然后必须启动通道。 它不像SSHJ那样直观。
// here: creation and configuration of session object
ChannelExec execChannel = null;
try {
execChannel = (ChannelExec) session.openChannel("exec");
execChannel.connect();
execChannel.setCommand(command);
execChannel.start();
} catch (JSchException ex) {
throw new IOException(ex);
} finally {
if (execChannel != null) {
execChannel.disconnect();
}
}
远程主机上的文件操作
所有库都通过远程计算机上的SFTP支持或多或少的理想文件操作。 在SSHJ中, SFTPClient也具有用于文件操作的方法。 方法的名称与Linux系统上的文件操作相同。 以下代码段显示了如何删除文件。
//here: creation and configuration of sshClient
try (SFTPClient sftpClient = sshClient.newSFTPClient()) {
sftpClient.rm(remotePath);
}
Commons VFS的核心功能是文件操作。 用法需要习惯。 必须解析文件对象,并且可以对其执行文件操作。
// here: creation and configuration of remoteRootDirectory
FileObject remoteFileObject = remoteRootDirectory.resolveFile(remotePath);
try {
remoteFileObject.delete();
} finally {
remoteFileObject.close();
}
JSch的SFTPClient ChannelSFTP也具有文件操作方法。 此通道支持大多数文件操作。 例如,必须通过ChannelExec上的简单外壳命令来完成远程计算机上的文件复制操作。
// here: creation and configuration of session
ChannelSftp sftpChannel = null;
try {
sftpChannel = (ChannelSftp) session.openChannel("sftp");
sftpChannel.connect();
sftpChannel.rm(remotePath);
} catch (SftpException | JSchException ex) {
throw new IOException(ex);
} finally {
if (sftpChannel != null) {
sftpChannel.disconnect();
}
}
结论
比较之后,我有两个收藏夹,SSHJ和Commons VFS。 SSHJ具有非常清晰的API,如果我需要通用的SSH客户端或通过SFTP进行文件操作就足够了,我会选择它。 如果我可以通过许多文件系统协议进行文件操作,或者不需要通用的SSH客户端,则可以选择Commons VFS。 对于这两种情况,我可以同时使用JSch来通过SSH执行命令。 Commons VFS的API已经习惯了。 但是在了解了背后的概念之后,API的用法就很简单了。
这个比较的整个源代码示例都托管在Github上 。
有用的链接
翻译自: https://www.javacodegeeks.com/2015/08/commons-vfs-sshj-and-jsch-in-comparison.html