勝手に Java リファレンス / FTP接続

戻る

Java でのFTP事情

 これを書いている段階では、JDK 1.4.1 が最新JDKなのですが、残念ながら、今の段階では、SUN標準のFTPクライアントは用意されていないようです。

 そこで、以下のアプローチのどれかを選択することになるでしょう。

  1. フリーのFTPクライアントクラスを利用する
  2. 外部のFTPソフトをJavaから使用する
  3. 自力でソケットを開いて、FTPをしゃべるクライアントをコーディングする
 2のアプローチでは、特定アプリケーションに依存してしまうため、Javaで書く意味が薄れてしまいます。
 3のアプローチは、RFCと格闘することになりそうです。
 よほどの理由がなければ、まず、1のアプローチを検討した方がいいでしょう。


フリーのFTPクライアントを利用する
  • Kasper's Classes

     この記事を書いている2002年11月の段階では、Java用に用意された FTP クライアントで、比較的マトモに動いてくれるフリーのものというと、Kasper さんの作成された Kasper's Classes 内の Kasper.net.ftp がお勧めです。

     1997年7月以来メンテナンスされていないようですので、若干不安はありますが、英語が読める方でしたら、分かりやすいサンプルのついた非常に丁寧なドキュメントがありますので、比較的簡単に使えます。
     特に、FTPプロトコルについての知識をお持ちの方でしたら、英語が読めなくても非常に簡単に使えると思います。

     ソースコードは有償公開というスタンスを取っておられるため、どうしてもソースがないとダメな人は別ですが、特に不具合が原因でソースを見なければならないということはありませんでした。

    Kasper.net.ftp を使用した、具体的なコーディングの例は以下のとおりです。



    ftpクライアントクラスのインスタンス生成などの準備

    以下のように、FTPClient クラスインスタンスと、FTPServerResponse クラスインスタンスを事前に生成しておきます。
    public FTPClient ftpClient = new FTPClient();
    public FTPServerResponse ftpResponse = null;

    ログインメソッドの例 ftpLoginCwd

     面倒なので、私の場合は、機能ごとにメソッドを作っています。
     基本的には、FTPClient クラスにFTPコマンドに対応するメソッドが用意されていますので、これを呼び出し、FTPServerResponse型のレスポンスを受信するという流れになります。

     このメソッドの引数と、その内容については、以下のとおりです。

    引数
    説明
    ftpClient 先に生成した、FTPClient型クラスインスタンス
    ftpServer 接続先FTPサーバーのFQDN

    例: "ftp.hoge.com" , "ftp.foo.com" ....等
    username FTPサーバーのログイン名
    password FTPサーバーのログインパスワード
    accountInfo

    FTP課金情報
    FTPサーバーが要求する場合のみ必要です。
    が、ほとんどの場合、""(空白文字列)で構いません。

    remoteDir ログイン後にFTPのCWDコマンドで移動する移動先ディレクトリのパス
    リモートのカレントディレクトリをどこに変更するか。ということです。

    例: "/cgi-bin/bulletinboard/logdata" , "/public_html/link"


     例外処理がかなりいいかげんになっています。必要に応じて追加したほうがよいでしょう。


        public void ftpLoginCwd(FTPClient ftpClient, String ftpServer, String username,
    String password, String accountInfo, String remoteDir) {
    try {
    // FTPサーバーへの接続
    System.out.println( ftpResponse = ftpClient.connect( ftpServer ) );
    if ( ftpResponse.getResponseCode() != FTPServerResponse.SERVER_READY ){
    System.exit(1);
    }
    // user コマンド
    System.out.println( ftpResponse = ftpClient.user(username) );

    // pass コマンド
    if ( ftpResponse.getResponseCode() != FTPServerResponse.PASSWORD_NEEDED ){
    System.exit(1);
    }
    System.out.println( ftpResponse = ftpClient.pass(password) );

    // acct FTP課金情報が必要か?
    if ( ftpResponse.getResponseCode() == FTPServerResponse.ACCOUNT_NEEDED ){
    // 必要ならFTP課金情報を送信する。
    System.out.println( ftpResponse = ftpClient.acct(accountInfo) );
    if ( ftpResponse.getResponseCode() != FTPServerResponse.USER_LOGGED_IN ){
    System.exit(1);
    }
    } // cwd ディレクトリ変更
    System.out.println( ftpResponse = ftpClient.cwd(remoteDir) );
    if ( ftpResponse.getResponseCode() != FTPServerResponse.FILE_ACTION_OKAY ){
    System.exit(1);
    }
    }
    catch (Exception e){
    System.err.println("Exception attempt to connecto to " + ftpServer);
    e.printStackTrace(); //スタックトレースの出力
    System.exit(1);
    }
    }

    FTPでのファイルアップロードメソッドの例 ftpStoreFile


     このメソッドは、ローカルに存在するファイル localFilename を、引数 remoteFilename で指定したファイル名で、FTPサーバーにアップロードします。
     このメソッドの引数に渡す ftpClient は、事前にログイン処理を済ませ、カレントディレクトリの移動も済んでいることが必要です。
     このメソッドでは、Passiveモードでアップロードを行っています。
     JavaからFTP接続するケースは、実際にはファイアーウォール越えになるケースが多いと考えられますので、特に問題がなければ、Activeモードで接続する必要はないと思います。(アプリケーションサーバーの前にファイアーウォールが無いってことはないでしょ?)

     下のコードでは、例外処理がいいかげんになっています。必要に応じて追加してご使用ください。

        public void ftpStoreFile( FTPClient ftpClient, String localFilename, String remoteFilename){
    try {
    // pasv コマンド(Passive モードに切り替える)
    System.out.println( ftpResponse = ftpClient.pasv() );
    if ( ftpResponse.getResponseCode() != FTPServerResponse.ENTERING_PASSIVE_MODE ){
    System.exit(1);
    }

    // stor コマンド / ファイル取得
    FTPServerResponse ftpResponses[] = ftpClient.stor(localFilename, remoteFilename);
    System.out.println(ftpResponses[0]);
    System.out.println(ftpResponses[1]);
    if ( ftpResponses[1].getResponseCode() != this.TRANSFER_COMPLETE ){
    System.exit(1);
    }

    }
    catch (Exception e){
    System.err.println("Exception attempt to connecto to " + ftpServer);
    e.printStackTrace(); //スタックトレースの出力
    System.exit(1);
    }

    FTPでのファイルダウンロードメソッドの例 ftpGetFile


     このメソッドは、FTPサーバーのカレントディレクトリに存在する remoteFilename をダウンロードし、ローカルマシンに引数 localFilename で指定されたファイル名で保存します。
     このメソッドの引数に渡す ftpClient は、事前にログイン処理を済ませ、カレントディレクトリの移動も済んでいることが必要です。
     また、このケースでも、前出のアッフロード同様Passiveモードを使用しています。
     Passive モードへの切り替えは、データコネクションの作成の度に必要なため、たとえば、1セッションで2回のファイル転送をするのであれば、2回Passiveモードへの切り替えが必要です。
     したがって、下記コードのPassiveモード切替は省略できません。

     また、ここではサンプルを掲載しませんが、FTPでは、カレントディレクトリのファイルリストの取得の際にも、データコネクションを張りますので、このときもPassiveモード切替が必要でしょう。
     
     下のコードでは、またしても、例外処理がいいかげんになっています。必要に応じて追加してご使用ください。

        public void ftpGetFile( FTPClient ftpClient, String remoteFilename, String localFilename ) {
    try {
    // pasv コマンド(Passive モードに切り替える)
    System.out.println( ftpResponse = ftpClient.pasv() );
    if ( ftpResponse.getResponseCode() != FTPServerResponse.ENTERING_PASSIVE_MODE ){
    System.exit(1);
    }

    // retr コマンド / ファイル取得
    FTPServerResponse ftpResponses[] = ftpClient.retr(remoteFilename, localFilename);
    System.out.println(ftpResponses[0]);
    System.out.println(ftpResponses[1]);
    if ( ftpResponses[1].getResponseCode() != this.TRANSFER_COMPLETE ){
    System.exit(1);
    }
    }
    catch (Exception e){
    System.err.println("Exception attempt to connecto to " + ftpServer);
    e.printStackTrace(); //スタックトレースの出力
    System.exit(1);
    }
    }