Apache MINAでSFTP接続
はじめに
必要に迫られてFTPS接続するJavaプログラムをSFTP接続するように書き換える際に、Apache MINAを使って動く形に書き下されたサンプルが見つからなかったので、そのメモ。
要件としてパスワード認証を使うというのもあった。
事前準備
必要なライブラリをダウンロードする。
Apache MINA / Apache SSHD
今回のメインライブラリ。
今回は、「Apache MINA 2.2.3」「Apache SSHD 2.11.0」を使用した。
Apache Commons IO
I/O周りを扱う上では何かと便利。
今回は、「Commons IO 2.16.1」を使用した。
メインプログラム
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.TimeZone; import org.apache.commons.io.IOUtils; import org.apache.sshd.client.SshClient; import org.apache.sshd.client.session.ClientSession; import org.apache.sshd.sftp.client.SftpClient; import org.apache.sshd.sftp.client.SftpClient.Attributes; import org.apache.sshd.sftp.client.SftpClient.CloseableHandle; import org.apache.sshd.sftp.client.SftpClient.DirEntry; import org.apache.sshd.sftp.client.SftpClientFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class SftpFile { private final String filename; private final String longFilename; private final Attributes attributes; public SftpFile(DirEntry entry) { filename = entry.getFilename(); longFilename = entry.getLongFilename(); attributes = entry.getAttributes(); /* System.out.println("===" + filename + "/" + longFilename + "==="); Attributes attrs = entry.getAttributes(); System.out.println(" type = " + attrs.getType()); System.out.println(" size = " + attrs.getSize()); System.out.println(" owner = " + attrs.getOwner()); System.out.println(" group = " + attrs.getGroup()); System.out.println(" userId = " + attrs.getUserId()); System.out.println(" groupId = " + attrs.getGroupId()); System.out.println(" permissions = " + attrs.getPermissions()); System.out.println(" accessTime = " + attrs.getAccessTime() + " (" + (attrs.getAccessTime() != null ? attrs.getAccessTime().toMillis() : 0) + ")<=>(" + System.currentTimeMillis() + ")"); System.out.println(" createTime = " + attrs.getCreateTime() + " (" + (attrs.getCreateTime() != null ? attrs.getCreateTime().toMillis() : 0) + ")<=>(" + System.currentTimeMillis() + ")"); System.out.println(" modifyTime = " + attrs.getModifyTime() + " (" + (attrs.getModifyTime() != null ? attrs.getModifyTime().toMillis() : 0) + ")<=>(" + System.currentTimeMillis() + ")"); System.out.println(" acl = " + attrs.getAcl()); System.out.println(" extensions = " + attrs.getExtensions()); System.out.println(" regularFile = " + attrs.isRegularFile()); System.out.println(" directory = " + attrs.isDirectory()); System.out.println(" symbolicLink = " + attrs.isSymbolicLink()); System.out.println(" other = " + attrs.isOther()); */ } public long getTimestamp() { return attributes.getModifyTime().toMillis(); } public boolean isDirectory() { return attributes.isDirectory(); } public String getFilename() { return this.filename; } public String getLongFilename() { return this.longFilename; } } class SftpConfig { public final String username; public final String password; public final String host; public final int port; public final String srcDir; public final String destDir; public SftpConfig(String username, String password, String host, int port, String srcDir, String destDir) { this.username = username; this.password = password; this.host = host; this.port = port; this.srcDir = srcDir; this.destDir = destDir; } } public class SftpTest { public static void main(String args[]) { Logger logger = LoggerFactory.getLogger(SftpTest.class); logger.debug("Logger is start."); try (SshClient client = SshClient.setUpDefaultClient()) { client.start(); SftpConfig[] config = { new SftpConfig("YOUR_NAME", "YOUR_PASSWORD", "localhost", 22, "test", "test"), }; for (int i = 0; i < config.length; ++i) { try (ClientSession session = client.connect(config[i].username, config[i].host, config[i].port).verify(60 * 1000).getSession()) { System.out.println("session started"); session.addPasswordIdentity(config[i].password); session.auth().verify(60 * 1000); try (SftpClient sftp = SftpClientFactory.instance().createSftpClient(session)) { Iterable<DirEntry> entries; try (CloseableHandle handle = sftp.openDir(config[i].srcDir)) { entries = sftp.listDir(handle); for (DirEntry entry: entries) { SftpFile file = new SftpFile(entry); System.out.println(file.getFilename()); System.out.println(file.getLongFilename()); TimeZone defaultTZ = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("GMT")); DateFormat df = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ssZ"); System.out.println(df.format(file.getTimestamp())); System.out.println(df.format(System.currentTimeMillis())); // デフォルトタイムゾーンを元に戻す。 TimeZone.setDefault(defaultTZ); String filename = file.getFilename(); logger.info(filename); if (filename.equals(".") || filename.equals("..")) { continue; } if (file.isDirectory()) { continue; } try (InputStream is = sftp.read(config[i].srcDir + "/" + filename)) { File dir = new File(config[i].destDir); if (!dir.exists()) { dir.mkdirs(); } FileOutputStream os = new FileOutputStream(new File(config[i].destDir, filename)); IOUtils.copy(is, os); } catch (IOException e) { e.printStackTrace(); logger.error(config[i].srcDir + "/" + filename + ": No such file", e); } } } } } } } catch (IOException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } } }
ビルドスクリプト
#! /bin/bash CP=. CP=${CP}:apache-mina-2.2.3/dist/mina-core-2.2.3.jar CP=${CP}:apache-mina-2.2.3/lib/commons-logging-1.0.3.jar CP=${CP}:apache-mina-2.2.3/lib/slf4j-api-1.7.36.jar CP=${CP}:apache-sshd-2.11.0/lib/sshd-core-2.11.0.jar CP=${CP}:apache-sshd-2.11.0/lib/sshd-common-2.11.0.jar CP=${CP}:apache-sshd-2.11.0/lib/sshd-sftp-2.11.0.jar CP=${CP}:apache-sshd-2.11.0/lib/slf4j-jdk14-1.7.32.jar CP=${CP}:commons-io-2.16.1/commons-io-2.16.1.jar javac -cp ${CP} SftpTest.java java -cp ${CP} SftpTest
実行結果
冒頭に警告がいくつか出るのだけど、今回は割愛。
. drwxr-xr-x 2 YOUR_NAME YOUR_NAME 27 Apr 29 03:16 . 2024-04-28T18:16:47+0000 2024-04-28T18:38:40+0000 Apr 29, 2024 3:38:40 AM SftpTest main INFO: . .. drwx------ 3 YOUR_NAME YOUR_NAME 74 Apr 29 03:16 .. 2024-04-28T18:16:18+0000 2024-04-28T18:38:40+0000 Apr 29, 2024 3:38:40 AM SftpTest main INFO: .. SftpTest.java -rwxr-x--- 1 YOUR_NAME YOUR_NAME 5392 Apr 29 03:16 SftpTest.java 2024-04-28T18:16:47+0000 2024-04-28T18:38:40+0000 Apr 29, 2024 3:38:40 AM SftpTest main INFO: SftpTest.java