sFTPによるファイル転送処理サンプル

JavaによるFTPのファイル転送を作ることになったのですが、セキュリティを考慮し、sFTPで通信経路を暗号化することになりました。
JavaによるsFTP通信に利用したのは、JCraftの「JSch – Java Secure Channel」というライブラリです。
また、今回は、ユーザー名とパスワードによる認証ではなく、privatekeyを読み込んでそれを利用して接続を行うという条件もありましたので、すこし手間取りました。

接続のサンプルはいくつか見つけたのですが、リモートサーバ側のシェルを実行するサンプルはあまり無かったので、備忘録的に上げておきたいと思います。

なお、ローカルの接続テストのために、フリーのSFTPサーバーを立てたのですが、「freeSSHd」を利用させていただきました。
リモートサーバのバッチファイルを実行するには、接続するユーザの「Shell」実行権限が付いていないといけないので、注意してください。

freeSSHdの設定画面で「Shell」実行権限が付いている場合、緑になっています。

 

 

 

 

 

 

以下は、実際のJavaサンプルです。

UserInfoの実装クラス

package jp.koji.jsch;

import com.jcraft.jsch.UserInfo;

public class MyUserInfo implements UserInfo {
    public String getPassword() {
        return null;
    }
    //PASSFRASEは空
    public String getPassphrase() {
        return "";
    }
    public boolean promptPassword(String arg0) {
        return true;
    }
    public boolean promptPassphrase(String arg0) {
        return true;
    }
    public boolean promptYesNo(String arg0) {
        return true;
    }
    public void showMessage(String arg0) {
    }
}

SampleTestクラス

package jp.koji.batch;


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.List;

import jp.koji.jsch.MyUserInfo;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;

public class JschTest {

    private static final String hostname = "XXXXXX";
    private static final String userid = "XXXXXXX";

    public static void main(String[] arg) throws JSchException, SftpException ,Exception{

        JSch jsch = new JSch();

        jsch.addIdentity("C:\PRIVATEKEY\keyname_pk");

        Session session = jsch.getSession(userid, hostname, 22);

        session.setUserInfo(new MyUserInfo());

        session.connect();

        //sftp MODEでの接続
        ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
        channel.connect();

        List list = channel.ls(".");
        System.out.println("---- ls");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

        channel.disconnect();

        //COMMAND実行 MODEでの接続
        ChannelExec channel2=(ChannelExec)session.openChannel("exec");
		channel2.setCommand("C:XXXXXXXXXXXSAMPLE.bat");
		channel2.connect();
		InputStreamReader inputStreamReader = null;
		inputStreamReader = new InputStreamReader( channel2.getInputStream(), "SJIS" );
		BufferedReader bufferedReader = null;
		bufferedReader = new BufferedReader( inputStreamReader );
		StringBuffer sblog = new StringBuffer("");
		while( true )
        {
            // 1文字取得
            int i = bufferedReader.read();
            if( i == -1 )
            {
                //-1で終了
                break;
            }

            // 出力
            sblog.append( (char)i );
        }
		System.out.println(sblog.toString());
		if (channel2.isClosed()) {
			System.out.println("status: "+channel2.getExitStatus());
		}

        channel2.disconnect();


        session.disconnect();
    }
}


こんな記事も関係あるかも。読んでみてね。

3 Responses to “sFTPによるファイル転送処理サンプル”

  1. 幸太郎 より:

    始めまして。通りがかりのものです。

    とても参考になりました。ありがとうございます。
    お陰様で、私も実装できたのですが、JSchですと
    DLがあまりにも遅く使い物になりません。。。
    ESエクスプローラーで2,3秒のものが、JSchだと20分近くかかります。
    何か良い手は無いものでしょうか?
    ESエクスプローラーは何をつかっているのでしょう??

    • admin より:

      「ESエクスプローラー」というのをはじめて聞きました。調べてみるとAndroidのアプリのようでしたが、私の認識あってますでしょうか。
      あっている前提で、Androidのアプリか何かで上記のサンプルを使われたと推測しますが。。。
      私が上記を使ったのは、PC上のバッチアプリですので、スマホでのパフォーマンスだとしたら、あまり高速化の方策は詳しくないですね。すみません。。
      それにしても、ESエクスプローラーで2、3秒のものがJSchだと20分とは、ファイルの容量が大きいのでしょうか?

      • 幸太郎 より:

        返信ありがとうございます。
        また説明不足で失礼しました。

        ESエクスプローラーはAndroidアプリになります。
        現在、AndroidアプリにてSFTP(DL)を実現しようと試みております。
        JSchを使えば実現することは可能なのですが、Androidですと、
        速度の問題がどうしても解決できません。
        BufferedInputStream/BufferedOutputStream を使って、
        whileでぐるぐる回してみると、JSchが一度にGetできるのは
        32Kでした。
        22Mのファイルですと、1分半ぐらいかかります。
        ESエクスプローラーですと、ものの数秒です。

        確かにJSchのソースをみると、32kの縛りがあるのですが、
        そこ(LOCAL_MAXIMUM_PACKET_SIZE)を大きいサイズ
        にしても32kのままでした。
        (修正したところが悪いのかもしれませんが・・・)

        悩ましいです・・・。

        前回投稿の訂正:
        >ESエクスプローラーで2、3秒のものがJSchだと20分
        正しくは
        20分かかるファイルは、ESエクスプローラーでは数十秒でした。

コメントを残す

サブコンテンツ

このページの先頭へ