Java FTP接続でファイル送信・ファイル受信する方法

JavaでFTP接続でファイル送信・ファイル受信する方法です。

JavaでFTP接続でファイル送信・ファイル受信する方法

JavaでFTPするためには Apache Commons Net を利用します。

ここでは JavaでFTP接続でファイル送信・ファイル受信する方法 をサンプルソースで紹介します。


環境構築

JavaでFTPするためには Apache Commons Net を利用するので、ダウンロードしてクラスパスに追加するなどの設定をおこないます。

Apache Commons Net - Download Commons Net

ここでは commons-net-3.3.jar をダウンロードして利用しています。

Mavenプロジェクトの場合はpom.xmlに下記を追加で。

<dependency>
  <groupId>commons-net</groupId>
  <artifactId>commons-net</artifactId>
  <version>3.3</version>
</dependency>

FTP送受信サンプルソース

FTP送受信のサンプルソースです。ここでは FtpConfig という Bean と Ftp というクラスを用意しています。説明はサンプルソースの後に記載しています。

FtpConfigクラス

FtpConfigは、FTP定義 Bean です。

package ftp;

import java.io.Serializable;

/**
 * <p><strong>FtpConfig</strong>は、FTP定義 Bean です。</p>
 */
public class FtpConfig implements Serializable {
  private static final long serialVersionUID = 1L;
  public String hostName;
  public int port;
  public String userName;
  public String password;
  public boolean binaryTransfer;
  public boolean usePassiveMode;
  public String hostPath;
  public String localPath;
  public String encoding;
}

Ftpクラス

Ftpは、FTPをおこなうクラスです。

package ftp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

/**
 * <p><strong>Ftp</strong>は、FTPをおこなうクラスです。</p>
 * <p>利用方法:</p>
 * <pre>
 *   try {
 *     Ftp ftp = new Ftp("192.168.0.100", 21, "sakaen", "password", false, false, "/home/sakaen", "C:/Temp/", "EUC_JP");
 *     if ( ftp.connect() )
 *       ftp.put();
 *     ftp.disconnect();
 *   } catch (Exception e) {}
 * </pre>
 * <p>ローカル側パスへは C:/Temp/sakaen.txt などのファイル名指定も可能です。</p>
 *
 * @author Sakakibara Engineering Office.
 * @version $Revision: 1.0 $ $Date: 2015.02.01 $ $Description: 新規作成 $
 */
public class Ftp {

  private FtpConfig config;
  private FTPClient client;
  private boolean isConnected;

  /**
   * コンストラクタ
   *
   * @param config FtpConfig
   */
  public Ftp(FtpConfig config) {
    this.config = config;
    this.isConnected = false;
  }

  /**
   * コンストラクタ
   *
   * @param hostName ホスト名(IPアドレス:127.0.0.1)
   * @param port ポート番号(21)
   * @param userName ユーザー
   * @param password パスワード
   * @param binaryTransfer バイナリ転送モード(true: Yes, false: No)
   * @param usePassiveMode パッシブモード(true: Yes, false: No)
   * @param hostPath ホスト側パス
   * @param localPath ローカル側パス
   * @param encoding エンコーディング(SJIS, MS932, EUC_JP など)
   */
  public Ftp(String hostName, int port, String userName, String password, boolean binaryTransfer, boolean usePassiveMode, String hostPath, String localPath, String encoding) {
    this.config = new FtpConfig();
    this.config.hostName = hostName;
    this.config.port = port;
    this.config.userName = userName;
    this.config.password = password;
    this.config.binaryTransfer = binaryTransfer;
    this.config.usePassiveMode = usePassiveMode;
    this.config.hostPath = hostPath;
    this.config.localPath = localPath;
    this.config.encoding = encoding;
    this.isConnected = false;
  }

  /**
   * パラメータチェック
   *
   * @return true: 正常, false: 異常
   */
  private boolean check() {
    boolean success = true;
    // ホスト名
    if ( isEmpty(this.config.hostName) ) {
      System.out.println("hostName Parameter Failed");
      success = false;
    }
    // ポート
    if ( this.config.port == 0 ) {
      System.out.println("port Parameter Failed");
      success = false;
    }
    // ユーザー名
    if ( isEmpty(this.config.userName) ) {
      System.out.println("userName Parameter Failed");
      success = false;
    }
    // パスワード
    if ( isEmpty(this.config.password) ) {
      System.out.println("password Parameter Failed");
      success = false;
    }
    // ホストパス
    if ( isEmpty(this.config.hostPath) ) {
      System.out.println("hostPath Parameter Failed");
      success = false;
    }
    // ローカルパス
    if ( isEmpty(this.config.localPath) ) {
      System.out.println("localPath Parameter Failed");
      success = false;
    }
    if ( isEmpty(this.config.encoding) ) {
      System.out.println("encoding Parameter Failed");
      success = false;
    }
    return success;
  }

  /**
   * 接続
   *
   * @return true: 正常, false: 異常
   * @throws Exception
   */
  public boolean connect() throws Exception {
    boolean success = check();
    if ( !success )
      return false;
    this.client = new FTPClient();
    System.out.println("connect....");
    this.client.setControlEncoding(this.config.encoding);
    client.connect(this.config.hostName, this.config.port);
    System.out.println("Connected to Server: " + this.config.hostName + " on " + this.client.getRemotePort());
    System.out.println(this.client.getReplyString());
    this.client.login(this.config.userName, this.config.password);
    System.out.println(client.getReplyString());
    if ( !FTPReply.isPositiveCompletion(this.client.getReplyCode()) ) {
      System.out.println("Login Failed");
      this.client.disconnect();
      return false;
    } else {
      this.isConnected = true;
    }
    // Binary転送モードの場合
    if ( this.config.binaryTransfer ) {
      this.client.setFileType(FTP.BINARY_FILE_TYPE);
      System.out.println("Mode binaryTransfer: true");
    }
    // PASVモードの場合
    if ( this.config.usePassiveMode ) {
      this.client.enterLocalPassiveMode();
      System.out.println("Mode usePassiveMode: ON");
    } else {
      this.client.enterLocalActiveMode();
      System.out.println("Mode usePassiveMode: OFF");
    }
    // ディレクトリ移動
    success = this.client.changeWorkingDirectory(this.config.hostPath);
    if ( !success ) {
      System.out.println("Server Directory Failed");
      this.client.disconnect();
      return false;
    }
    System.out.println(this.client.getReplyString());
    success = FTPReply.isPositiveCompletion(this.client.getReplyCode());
    System.out.println("Connection: " + (success ? "OK" : "NG"));
    System.out.println("-----------------------------------");
    return success;
  }

  /**
   * 切断
   *
   * @return true: 正常, false: 異常
   * @throws Exception
   */
  public boolean disconnect() throws Exception {
    if ( this.isConnected ) {
      client.logout();
      System.out.println(client.getReplyString());
      if ( client.isConnected() ) client.disconnect();
    }
    return true;
  }

  /**
   * 送信
   *
   * @return true: 正常, false: 異常
   * @throws Exception
   */
  public boolean put() throws Exception {
    boolean success = true;
    if ( !this.isConnected )
      success = connect();
    if ( success ) {
      // ディレクトリ移動
      success = this.client.changeWorkingDirectory(this.config.hostPath);
      if ( !success ) {
        System.out.println("Server Directory Failed");
        this.client.disconnect();
        return false;
      }
      return putFiles(new File(this.config.localPath), this.config.hostPath + (this.config.hostPath.endsWith("/") ? "" : "/"));
    }
    return success;
  }

  /**
   * ファイル送信
   *
   * @param file FTPFile
   * @param hostPath ホスト側パス
   * @throws Exception
   */
  private boolean putFiles(File file, String hostPath) throws Exception {
    boolean success = true;
    if ( file.isFile() ) {
      FileInputStream is = null;
      try {
        is = new FileInputStream(file);
        System.out.println("PUT File Name: "  + file.getName());
        this.client.storeFile(hostPath + file.getName(), is);
        is.close();
        System.out.println("FTP PUT Completed");
      } catch ( Exception e ) {
        System.out.println("FTP PUT Failed: " + file.getName());
        System.out.println(e.getMessage());
        success = false;
      } finally {
        if ( is != null )
          is.close();
      }
    } else if ( file.isDirectory() ) {
      String dirName = hostPath + file.getName() + "/";
      System.out.println("Make Directory: " + dirName);
      // ディレクトリがなければ作る
      success = this.client.makeDirectory(dirName);
      if ( success ) {
        success = this.client.changeWorkingDirectory(dirName);
      } else {
        // ディレクトリが作れない場合、移動してみる
        success = this.client.changeWorkingDirectory(dirName);
        if ( !success ) {
          System.out.println("Server Directory Failed: " + dirName);
          return success;
        }
      }
      System.out.println("-----------------------------------");
      File[] files = file.listFiles();
      for ( File f : files ) {
        success = putFiles(f, dirName);
        if ( !success )
          return success;
          }
    } else {
    }
    return success;
  }

  /**
   * 受信
   */
  public boolean get() throws Exception {
    boolean success = true;
    if ( !this.isConnected )
      success = connect();
    if ( success ) {
      // ディレクトリ移動
      success = this.client.changeWorkingDirectory(this.config.hostPath);
      if ( !success ) {
        System.out.println("Server Directory Failed");
        this.client.disconnect();
        return false;
      }
      String fileNames[] = this.client.listNames();
      if ( fileNames != null ) {
        for ( int i = 0; i < fileNames.length; i++ ) {
          System.out.println("Get File Name: "  + fileNames[i]);
        }
      }
      System.out.println("-----------------------------------");
      for (FTPFile f : this.client.listFiles()) {
        getFiles(f, this.config.localPath);
      }
    }
    return success;
  }

  /**
   * ファイル取得
   *
   * @param file FTPFile
   * @param localPath ローカル側パス
   * @throws Exception
   */
  private boolean getFiles(FTPFile file, String localPath) throws Exception {
    boolean success = true;
    if ( !file.getName().equals(".")&&!file.getName().equals("..") ) {
      String currentDir = client.printWorkingDirectory();
      if ( file.isFile() ) {
        String filename = file.getName();
        filename = new String(filename.getBytes("MS932"), "UTF-8");
        String utf8filename = client.printWorkingDirectory() + (currentDir.endsWith("/") ? "" : "/") + file.getName();
        System.out.println("Get File Name: " + filename);
        System.out.println("Get UTF8 File Name: " + utf8filename);
        String localPathName = localPath + (localPath.endsWith("/") ? "" : "/") + filename;
        System.out.println("Local Path Name: " + localPathName);
        FileOutputStream os = null;
        try {
          os = new FileOutputStream(localPathName);
          client.retrieveFile(utf8filename, os);
          os.close();
          System.out.println("FTP GET Completed");
        } catch ( Exception e ) {
          System.out.println("FTP GET Failed: " + filename);
          System.out.println(e.getMessage());
          success = false;
        } finally {
          if ( os != null )
            os.close();
        }
      } else if ( file.isDirectory() ) {
        File localDir = new File(localPath + (localPath.endsWith("/") ? "" : "/") + file.getName());
        String path = localPath;
        if ( !localDir.exists() ) {
          localDir.mkdirs();
          path = localPath + (localPath.endsWith("/") ? "" : "/") + file.getName();
        }
        success = client.doCommand("CWD", client.printWorkingDirectory() + (currentDir.endsWith("/") ? "" : "/") + file.getName());
        for (FTPFile f : client.listFiles()) {
          success = getFiles(f, path);
          if ( !success )
            break;
        }
        //client.doCommand("CDUP", "");
      }
    }
    return success;
  }

  /**
   * 空文字列チェック
   *
   * @param value 文字列
   * @return null または 空文字列 なら true , それ以外なら false
   */
  public boolean isEmpty(String value) {
    if ( value == null || value.length() == 0 )
      return true;
    else
      return false;
  }

  /**
   * ホスト側パスセット
   *
   * @param hostPath ホスト側パス
   */
  public void setHostPath(String hostPath) {
    this.config.hostPath = hostPath;
  }

  /**
   * ローカル側パスセット
   *
   * @param localPath ローカル側パス
   */
  public void setLocalPath(String localPath) {
    this.config.localPath = localPath;
  }
}

サンプルソースの説明

まず FTPClient をインスタンス化し setControlEncoding メソッドにてエンコードを設定します。次に connect メソッドを使って指定サーバーへ接続します。login メソッドを使ってログインすれば、ファイルを送信したり受信したりできます。

ファイルを送信する場合 storeFile メソッドの引数に FileInputStream を指定します。サンプルソースの putFiles メソッドでは、FTPサーバ上に指定ディレクトリがない場合、新規に作成しています。

ファイルを受信する場合 retrieveFile メソッドの引数に ファイル名と FileOutputStream を指定します。サンプルソースの getFiles メソッドでは、ローカル上に指定ディレクトリがない場合、新規に作成しています。

FTPClientの主なメソッド

サンプルソースで使った FTPClient の主なメソッドです。

メソッド説明
setControlEncodingエンコーディング(SJIS, MS932, EUC_JPなど)を指定します。
connectIPアドレスやコンピュータ名、ポート番号を指定してFTPサーバーへ接続します。
loginユーザー名、パスワードを指定してFTPサーバーへログインします。
setFileType転送モードを指定します。(BINARY_FILE_TYPE or ASCII_FILE_TYPE)
enterLocalPassiveModePASVモードの場合、メソッドを呼び出します。
enterLocalActiveModePASVモード以外の場合、メソッドを呼び出します。
changeWorkingDirectoryディレクトリを移動します。
logoutログアウトします。
isConnectedFTPサーバーへ接続されているかどうかを判断します。
disconnectFTPサーバーへの接続を切断します。
storeFileFTPサーバーへファイルを送信します。
printWorkingDirectory現在の作業ディレクトリのパス名を返します。
retrieveFileFTPサーバーからファイルを受信します。
doCommandコマンドを発行し、応答を待ちます。

FTP送受信テスト

それでは FTP送受信のテストをしてみましょう。テストソースはこんな感じです。

public class FtpTest {
  public static void main(String[] args) {
    try {
      Ftp ftp = new Ftp("192.168.0.100", 21, "sakaen", "password", false, false, "/home/sakaen", "C:/Temp/", "EUC_JP");
      if ( ftp.connect() ) {
        ftp.get();
        ftp.setLocalPath("C:/Temp/サカエン");
        ftp.put();
        ftp.disconnect();
      }
    } catch (Exception e) {
      System.out.println(e.getMessage());
    }
  }
}

Ftp クラスへのパラメーターは環境に合わせて変更してください。

まず、FTPサーバー上からファイルを受信します。次に、ローカルのディレクトリを移動してFTPサーバへファイルを送信します。

ローカル側のディレクトリ内

ローカル側のディレクトリ内の状態を確認しましょう。

C:/Temp の中には サカエン というディレクトリのみ存在します。

C:/Temp の中には サカエン というディレクトリのみ存在します。

C:/Temp/サカエン の中には saka-en というディレクトリと サカエン.txt というファイルが存在します。

C:/Temp/サカエン の中には saka-en というディレクトリと サカエン.txt というファイルが存在します。

C:/Temp/サカエン/saka-en の中には saka-en.txt というファイルが存在します。

C:/Temp/サカエン/saka-en の中には saka-en.txt というファイルが存在します。

FTPサーバ側のディレクトリ内

FTPサーバ側のディレクトリ内状態を確認しましょう。

/home/sakaen の中には Test というディレクトリが存在します。

/home/sakaen の中には Test というディレクトリが存在します。

/home/sakaen/Test の中には Test2 というディレクトリと text1.txt というファイルが存在します。

/home/sakaen/Test の中には Test2 というディレクトリと text1.txt というファイルが存在します。

/home/sakaen/Test/Test2 の中には text2.txt というファイルが存在します。

/home/sakaen/Test/Test2 の中には text2.txt というファイルが存在します。

FTP送受信テスト結果

実行結果はこんな感じになります。

ローカル側

C:/Temp/Test というディレクトリが増えました。

C:/Temp/Test というディレクトリが増えました。

C:/Temp/Test の中には Test2 ディレクトリと text1.txt ファイルが存在します。

C:/Temp/Test の中には Test2 ディレクトリと text1.txt ファイルが存在します。

C:/Temp/Test/Test2 の中には text2.txt ファイルが存在します。

C:/Temp/Test/Test2 の中には text2.txt ファイルが存在します。

FTP受信がうまくいったようですね。

FTPサーバー側

/home/sakaen の中には サカエン というディレクトリが増えました。

/home/sakaen の中には サカエン というディレクトリが増えました。

/home/sakaen/サカエン の中には saka-en ディレクトリと サカエン.txt ファイルが存在します。

/home/sakaen/サカエン の中には saka-en ディレクトリと サカエン.txt ファイルが存在します。

/home/sakaen/サカエン/saka-en の中には saka-en.txt ファイルが存在します。

/home/sakaen/サカエン/saka-en の中には saka-en.txt ファイルが存在します。

FTP送信がうまくいったようですね。

参考サイト

おつかれさまでした。

この記事がお役に立ちましたら シェア をお願いいたします。