JavaでSFTPに接続する方法
Javaを使ったSFTPへの接続、ファイルのリストアップ、アップロード、ダウンロードの方法についてご説明します。
本記事では、SFTP サーバーに接続してやり取りするための Java コードの書き方についてご説明します。SFTPは広く使われている標準的で安全なプロトコルで、主な目的は、安全なファイルやデータ転送の提供です。サーバーへの接続を行う際には、いくつかの簡単なステップを習うだけなので、この記事が終わるころには、簡単にこれらが出来るでしょう。
必要条件
SFTP サーバーへの接続に使われる Java ライブラリはいくつかあります。ここでは、JavaのみでSSH2を実装した Jsch を使うことにします。以下の例は、JavaプロジェクトにJSCHを追加する方法のほんの一部です:
Mavenを使用:
<dependency>
<groupId>com.github.mwiede</groupId>
<artifactId>jsch</artifactId>
<version>0.2.0</version>
</dependency>
Gradleを使用:
implementation 'com.github.mwiede:jsch:0.2.0'
SFTPへの接続
本記事では、SFTP サーバーに接続するために必要な情報をすべて URI 形式で格納した SFTPTOGO_URL という環境変数を使います:sftp://user:password@host.
この変数は URI.parse を使って URI の部分を抽出し、リモートサーバーのホストキーは ~/.ssh/known_hosts
を使って自動的に検証されます。
SftpClient クラスのインスタンスを作成する際に、ホスト、ユーザ名、およびオプションでポート (デフォルトは 22) を渡します。パスワードで認証するには、authPassword
関数を使い、公開鍵認証を使って認証するには、秘密鍵へのパスとパス文字列を authKey
関数に渡します。
package com.sftptogo;
import com.jcraft.jsch.*;
import com.sftptogo.util.Util;
import java.util.Properties;
import java.util.Vector;
/**
* A simple SFTP client using JSCH http://www.jcraft.com/jsch/
*/
public final class SftpClient {
private final String host;
private final int port;
private final String username;
private final JSch jsch;
private ChannelSftp channel;
private Session session;
/**
* @param host remote host
* @param port remote port
* @param username remote username
*/
public SftpClient(String host, int port, String username) {
this.host = host;
this.port = port;
this.username = username;
jsch = new JSch();
}
/**
* Use default port 22
*
* @param host remote host
* @param username username on host
*/
public SftpClient(String host, String username) {
this(host, 22, username);
}
/**
* Authenticate with remote using password
*
* @param password password of remote
* @throws JSchException If there is problem with credentials or connection
*/
public void authPassword(String password) throws JSchException {
session = jsch.getSession(username, host, port);
//disable known hosts checking
//if you want to set knows hosts file You can set with jsch.setKnownHosts("path to known hosts file");
var config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setPassword(password);
session.connect();
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
}
public void authKey(String keyPath, String pass) throws JSchException {
jsch.addIdentity(keyPath, pass);
session = jsch.getSession(username, host, port);
//disable known hosts checking
//if you want to set knows hosts file You can set with jsch.setKnownHosts("path to known hosts file");
var config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
}
}
ファイル一覧
接続ができたので、リモート SFTP サーバー上のファイル一覧が取得できます。ラッパー関数 listFiles
は、チャネルのls
関数を呼び出してリモートファイルのリストを取得し、それを反復処理で各ファイルのパーミッション、ファイル名、サイズを表示します。
/**
* List all files including directories
*
* @param remoteDir Directory on remote from which files will be listed
* @throws SftpException If there is any problem with listing files related to permissions etc
* @throws JSchException If there is any problem with connection
*/
@SuppressWarnings("unchecked")
public void listFiles(String remoteDir) throws SftpException, JSchException {
if (channel == null) {
throw new IllegalArgumentException("Connection is not available");
}
System.out.printf("Listing [%s]...%n", remoteDir);
channel.cd(remoteDir);
Vector<ChannelSftp.LsEntry> files = channel.ls(".");
for (ChannelSftp.LsEntry file : files) {
var name = file.getFilename();
var attrs = file.getAttrs();
var permissions = attrs.getPermissionsString();
var size = Util.humanReadableByteCount(attrs.getSize());
if (attrs.isDir()) {
size = "PRE";
}
System.out.printf("[%s] %s(%s)%n", permissions, name, size);
}
}
ファイルのアップロード
次のステップは、ファイルのアップロードです。このクラスのuploadFile
は、2つの引数と取っており、localPath(アップロードするファイル)とremotePath(サーバー上のアップロード先)です。呼び出しの例は次のようになります: client.uploadFile("./local.txt", "/remote.txt");
/**
* Upload a file to remote
*
* @param localPath full path of location file
* @param remotePath full path of remote file
* @throws JSchException If there is any problem with connection
* @throws SftpException If there is any problem with uploading file permissions etc
*/
public void uploadFile(String localPath, String remotePath) throws JSchException, SftpException {
System.out.printf("Uploading [%s] to [%s]...%n", localPath, remotePath);
if (channel == null) {
throw new IllegalArgumentException("Connection is not available");
}
channel.put(localPath, remotePath);
}
ファイルのダウンロード
最後は、ファイルのダウンロードだけです。 downloadFile
関数は、2つの引数を取っており、remotePath(ダウンロードするファイル)とlocalPath(ファイルのダウンロード先)です。client.downloadFile("/remote.txt", "./download.txt");
のように関数を呼び出すことになります。
/**
* Download a file from remote
*
* @param remotePath full path of remote file
* @param localPath full path of where to save file locally
* @throws SftpException If there is any problem with downloading file related permissions etc
*/
public void downloadFile(String remotePath, String localPath) throws SftpException {
System.out.printf("Downloading [%s] to [%s]...%n", remotePath, localPath);
if (channel == null) {
throw new IllegalArgumentException("Connection is not available");
}
channel.get(remotePath, localPath);
}
まとめ
これで完了です!もし、このプログラムを最初から最後まで通して実行したい場合は、プロジェクトの構築と実行方法について、こちらの説明に従ってください。
package com.sftptogo;
import com.jcraft.jsch.*;
import com.sftptogo.util.Util;
import java.util.Properties;
import java.util.Vector;
/**
* A simple SFTP client using JSCH http://www.jcraft.com/jsch/
*/
public final class SftpClient {
private final String host;
private final int port;
private final String username;
private final JSch jsch;
private ChannelSftp channel;
private Session session;
/**
* @param host remote host
* @param port remote port
* @param username remote username
*/
public SftpClient(String host, int port, String username) {
this.host = host;
this.port = port;
this.username = username;
jsch = new JSch();
}
/**
* Use default port 22
*
* @param host remote host
* @param username username on host
*/
public SftpClient(String host, String username) {
this(host, 22, username);
}
/**
* Authenticate with remote using password
*
* @param password password of remote
* @throws JSchException If there is problem with credentials or connection
*/
public void authPassword(String password) throws JSchException {
session = jsch.getSession(username, host, port);
//disable known hosts checking
//if you want to set knows hosts file You can set with jsch.setKnownHosts("path to known hosts file");
var config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setPassword(password);
session.connect();
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
}
public void authKey(String keyPath, String pass) throws JSchException {
jsch.addIdentity(keyPath, pass);
session = jsch.getSession(username, host, port);
//disable known hosts checking
//if you want to set knows hosts file You can set with jsch.setKnownHosts("path to known hosts file");
var config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
}
/**
* List all files including directories
*
* @param remoteDir Directory on remote from which files will be listed
* @throws SftpException If there is any problem with listing files related to permissions etc
* @throws JSchException If there is any problem with connection
*/
@SuppressWarnings("unchecked")
public void listFiles(String remoteDir) throws SftpException, JSchException {
if (channel == null) {
throw new IllegalArgumentException("Connection is not available");
}
System.out.printf("Listing [%s]...%n", remoteDir);
channel.cd(remoteDir);
Vector<ChannelSftp.LsEntry> files = channel.ls(".");
for (ChannelSftp.LsEntry file : files) {
var name = file.getFilename();
var attrs = file.getAttrs();
var permissions = attrs.getPermissionsString();
var size = Util.humanReadableByteCount(attrs.getSize());
if (attrs.isDir()) {
size = "PRE";
}
System.out.printf("[%s] %s(%s)%n", permissions, name, size);
}
}
/**
* Upload a file to remote
*
* @param localPath full path of location file
* @param remotePath full path of remote file
* @throws JSchException If there is any problem with connection
* @throws SftpException If there is any problem with uploading file permissions etc
*/
public void uploadFile(String localPath, String remotePath) throws JSchException, SftpException {
System.out.printf("Uploading [%s] to [%s]...%n", localPath, remotePath);
if (channel == null) {
throw new IllegalArgumentException("Connection is not available");
}
channel.put(localPath, remotePath);
}
/**
* Download a file from remote
*
* @param remotePath full path of remote file
* @param localPath full path of where to save file locally
* @throws SftpException If there is any problem with downloading file related permissions etc
*/
public void downloadFile(String remotePath, String localPath) throws SftpException {
System.out.printf("Downloading [%s] to [%s]...%n", remotePath, localPath);
if (channel == null) {
throw new IllegalArgumentException("Connection is not available");
}
channel.get(remotePath, localPath);
}
/**
* Delete a file on remote
*
* @param remoteFile full path of remote file
* @throws SftpException If there is any problem with deleting file related to permissions etc
*/
public void delete(String remoteFile) throws SftpException {
System.out.printf("Deleting [%s]...%n", remoteFile);
if (channel == null) {
throw new IllegalArgumentException("Connection is not available");
}
channel.rm(remoteFile);
}
/**
* Disconnect from remote
*/
public void close() {
if (channel != null) {
channel.exit();
}
if (session != null && session.isConnected()) {
session.disconnect();
}
}
}
Javaを使ったSFTPへの接続ができました。お疲れ様でした。
その他のコードサンプルはGithubでご確認ください。