Java ソースコード FTPgui.java
FTPクライアントを実装するJavaプログラミングの参考ソースコード。
FTPサーバーURL、ユーザ名、パスワードを入力後、「接続」jButtonConnectボタンによりサーバーに接続する。
「一覧」ボタンjButtonNLSTでサーバー内のファイル一覧表示、
「PWD」ボタンjButtonPWDで現在のディレクトリ表示、
「CWD」ボタンjButtonCWDで、CWD移動先ディレクトリjTextCWD内に指定されているディレクトリへ移動、
親ディレクトリに戻るときは、「..」を指定すればよい。
「送信」ボタンjButtonSendで、FileChooserダイアログが表示され、選択したファイルをサーバーに送信する。
「受信」ボタンjButtonReceiveで「受信ファイル名」jTextReceiveFileに指定されたサーバー内のファイルをこちらへ受信。
「切断」ボタンjButtonDisconでFTPサーバーとの接続を切断します。
それぞれのコマンド送信後にサーバーからのレスポンスメッセージをjTextAreaLogに表示していきます。
java01.phpで、ごく基本的なFTP送信のみの処理を示しましたが、アクセスログを見るとアクセスが非常に多いようなので、
送受信両方に加えファイルリスト表示やPWD、CWDコマンドまで実装しました。実際に試してみる際にはPassiveモードでないと
インターネット上の本物のFTPサーバーで試してみることができない(場合がほとんど)ので、Passiveモード固定としました。
Passiveモードでのデータリンクのしかたなどじっくり検討して、理解してみてください。
例によって、NetBeansで作成したソースファイルの、人間が入力した部分のみを掲載します。
各コンポーネント名がわかっていれば問題ありませんよね。
なお、通信が行われない状態でしばらくするとFTPサーバーは接続を自動的に切断します。切断に気づかず「あれ、エラーだ。」と慌てないでください。
TCP/IPソケットプログラミング Java編
↑この本はJavaの通信プログラムの基本理解に手頃です。あまり厚くないのでとっつきやすい。
/**
*
* @author Kom. of sys9.org
*/
import java.io.*;
import java.net.Socket;
import java.util.*;
import javax.swing.JFileChooser;
public class FTPgui extends javax.swing.JFrame {
Socket socket ;
private BufferedWriter bufWriter ; // コントロールチャンネル用出力ストリーム
private BufferedReader bufReader ; // コントロールチャンネル用入力ストリーム
private InputStream inpStream = null;
private InputStreamReader inpStreamRd = null;
private static final String BR = System.getProperty("line.separator");
public FTPgui() {
initComponents();
}
private void jButtonConnectActionPerformed(java.awt.event.ActionEvent evt) {
try {
connect();
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
private void jButtonNLSTActionPerformed(java.awt.event.ActionEvent evt) {
try {
getFileList();
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
private void jButtonDisconActionPerformed(java.awt.event.ActionEvent evt) {
try {
disconnect();
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
private void jButtonPWDActionPerformed(java.awt.event.ActionEvent evt) {
try {
pwd();
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
private void jButtonSendActionPerformed(java.awt.event.ActionEvent evt) {
File file=null;
JFileChooser filechooser = new JFileChooser("c:\\");
int selected = filechooser.showOpenDialog(this);
if (selected == JFileChooser.APPROVE_OPTION){
file = filechooser.getSelectedFile();
try {
sendFile(file);
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}else if (selected == JFileChooser.CANCEL_OPTION){
//Cansel
}else if (selected == JFileChooser.ERROR_OPTION){
//Error
}
}
private void jButtonReceiveActionPerformed(java.awt.event.ActionEvent evt) {
if(!jTextReceiveFile.getText().equals("")){
try {
receiveFile(jTextReceiveFile.getText());
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
}
private void jButtonCWDActionPerformed(java.awt.event.ActionEvent evt) {
//ディレクトリ移動。親ディレクトリに移動するときは「..」を
//指定すればよい。
if(!jTextCWD.getText().equals("")){
try {
cwd();
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
}
private void connect() throws IOException
{
//サーバー接続用ソケット作成
socket = new Socket( jTextServerAdrs.getText(),
Integer.valueOf(jTextServerPort.getText())) ;
//入出力ストリーム作成
inpStream = socket.getInputStream();
inpStreamRd =new InputStreamReader(inpStream);
bufReader = new BufferedReader(inpStreamRd);
bufWriter = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream() ) ) ;
//レスポンスコード保持用
String response = bufReader.readLine();
jTextAreaLog.append(response+BR);
if (!response.startsWith("220 ")) {
throw new IOException(
"レスポンスコードが正しい値ではありません。: " + response);
}
sendLine("USER " + jTextUser.getText());
response = bufReader.readLine();
jTextAreaLog.append(response+BR);
if (!response.startsWith("331 ")) {
throw new IOException(
"USERに対してのレスポンスコードが正しい値ではありません。: "
+ response);
}
char[] password = jPassField.getPassword();
String passStr = new String(password);
sendLine("PASS " + passStr);
response = bufReader.readLine();
jTextAreaLog.append(response+BR);
if (!response.startsWith("230 ")) {
throw new IOException(
"PASSに対してのレスポンスコードが正しい値ではありません。: "
+ response);
}
}
public synchronized void disconnect() throws IOException {
try {
sendLine("QUIT");
String response = bufReader.readLine();
jTextAreaLog.append(response+BR);
}
finally {
socket = null;
}
}
private void sendLine(String line) throws IOException {
//1行送信をbufWriterに行う。
if (socket == null) {
jTextAreaLog.append("未接続です。"+BR);
throw new IOException("未接続です。");
}
try {
bufWriter.write(line +BR);
bufWriter.flush();
}
catch (IOException e) {
socket = null;
throw e;
}
}
private void receiveFile(String fname) throws IOException {
//ファイルを受信する。いまどきPORTモードしか使えないサーバーは
//ないだろうから、PASSIVEモード固定。
sendLine("PASV");
String response = bufReader.readLine();
jTextAreaLog.append(response+BR);
if (!response.startsWith("227 ")) {
throw new IOException("Passiveモードが利用できません。: " + response);
}
//サーバーからのレスポンスメッセージを解析し、
//データコネクション用ポートを計算
String ip = null;
int port = -1;
int opening = response.indexOf('(');
int closing = response.indexOf(')', opening + 1);
if (closing > 0) {
String dataLink = response.substring(opening + 1, closing);
StringTokenizer tokenizer = new StringTokenizer(dataLink, ",");
try {
ip = tokenizer.nextToken() + "." + tokenizer.nextToken() +
"." + tokenizer.nextToken() + "." + tokenizer.nextToken();
port = Integer.parseInt(tokenizer.nextToken()) * 256 +
Integer.parseInt(tokenizer.nextToken());
}
catch (Exception e) {
throw new IOException(
"データコネクション情報が正しく受信できません。: "
+ response);
}
}
Socket dataSocket = new Socket(ip, port);
sendLine("RETR "+ fname);
response = bufReader.readLine();
jTextAreaLog.append(response+BR);
int readLength = 0;
BufferedInputStream bufIn =
new BufferedInputStream(dataSocket.getInputStream());
BufferedOutputStream bufOut =
new BufferedOutputStream(new FileOutputStream("c:\\"+fname));
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = bufIn.read(buffer)) != -1) {
bufOut.write(buffer, 0, bytesRead);
}
bufOut.flush();
bufOut.close();
bufIn.close();
response = bufReader.readLine();
jTextAreaLog.append(response+BR);
return;
}
private boolean sendFile(File file) throws IOException {
//ファイルを送信する。いまどきPORTモードしか使えないサーバーは
//ないだろうから、PASSIVEモード固定。
String filename = file.getName();
BufferedInputStream bufIn =
new BufferedInputStream(new FileInputStream(file));
sendLine("PASV");
String response = bufReader.readLine();
jTextAreaLog.append(response+BR);
if (!response.startsWith("227 ")) {
throw new IOException("Passiveモードが利用できません。: "
+ response);
}
//サーバーからのレスポンスメッセージを解析し、
//データコネクション用ポートを計算
String ip = null;
int port = -1;
int opening = response.indexOf('(');
int closing = response.indexOf(')', opening + 1);
if (closing > 0) {
String dataLink = response.substring(opening + 1, closing);
StringTokenizer tokenizer = new StringTokenizer(dataLink, ",");
try {
ip = tokenizer.nextToken() + "." + tokenizer.nextToken() +
"." + tokenizer.nextToken() + "." + tokenizer.nextToken();
port = Integer.parseInt(tokenizer.nextToken()) * 256 +
Integer.parseInt(tokenizer.nextToken());
}
catch (Exception e) {
throw new IOException(
"データコネクション情報が正しく受信できません。: "
+ response);
}
}
sendLine("STOR " + filename);
Socket dataSocket = new Socket(ip, port);
response = bufReader.readLine();
jTextAreaLog.append(response+BR);
if (!response.startsWith("150 ")) {
throw new IOException("ファイル送信ができません。: "
+ response);
}
BufferedOutputStream bufOut =
new BufferedOutputStream(dataSocket.getOutputStream());
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = bufIn.read(buffer)) != -1) {
bufOut.write(buffer, 0, bytesRead);
}
bufOut.flush();
bufOut.close();
dataSocket.close();
bufIn.close();
response = bufReader.readLine();
jTextAreaLog.append(response+BR);
return response.startsWith("226 ");//226ならば正常に終了
}
public String pwd() throws IOException {
//PWDコマンドを送信し、response文字列を返す。
sendLine("PWD");
String dir = null;
String response = bufReader.readLine();
jTextAreaLog.append(response+BR);
if (response.startsWith("257 ")) {
// ダブルクォートを取り除く
int beginIdx = response.indexOf("\"");
int endIdx = response.indexOf("\"", beginIdx + 1);
String result = response.substring(beginIdx + 1, endIdx);
dir = response;
}
return dir;
}
public String cwd() throws IOException {
//CWDコマンドを送信し、response文字列を返す。
sendLine("CWD "+jTextCWD.getText());
String dir = null;
String response = bufReader.readLine();
jTextAreaLog.append(response+BR);
if (response.startsWith("250 ")) {
// ダブルクォートを取り除く
int beginIdx = response.indexOf("\"");
int endIdx = response.indexOf("\"", beginIdx + 1);
String result = response.substring(beginIdx + 1, endIdx);
dir = response;
}
return dir;
}
public boolean setBin() throws IOException {
sendLine("TYPE I");
String response = bufReader.readLine();
jTextAreaLog.append(response+BR);
return (response.startsWith("200 "));
}
public boolean setAscii() throws IOException {
sendLine("TYPE A");
String response = bufReader.readLine();
jTextAreaLog.append(response+BR);
return (response.startsWith("200 "));
}
private String[] getFileList() throws IOException {
//ファイルリストの入ったString型配列を返す。
//現バージョンではこの配列は使っていない。
Vector flist_array = new Vector();
sendLine("PASV");
String response = bufReader.readLine();
jTextAreaLog.append(response+BR);
if (!response.startsWith("227 ")) {
throw new IOException("Passiveモードが利用できません。: "
+ response);
}
String ip = null;
int port = -1;
int opening = response.indexOf('(');
int closing = response.indexOf(')', opening + 1);
if (closing > 0) {
String dataLink = response.substring(opening + 1, closing);
StringTokenizer tokenizer = new StringTokenizer(dataLink, ",");
try {
ip = tokenizer.nextToken() + "." + tokenizer.nextToken() +
"." + tokenizer.nextToken() + "." + tokenizer.nextToken();
port = Integer.parseInt(tokenizer.nextToken()) * 256 +
Integer.parseInt(tokenizer.nextToken());
}
catch (Exception e) {
throw new IOException(
"データコネクション情報が正しく受信できません。: " + response);
}
}
//NLSTを使用すると、ファイル(ディレクトリ)名のみが得られる。
//LISTを使用すると
// drwxr-xr-x 1 ftp ftp 0 Jul 12 12:47 Windows
// -rw-r--r-- 1 ftp ftp 471 Jul 10 13:32 arr.txt
//のような形でパーミッションやタイムスタンプを含む全ての情報が得られる。
//FTPクライアントソフトとしてファイラ機能を充実させるならば、
//この情報を分解してJTableなどの中に表示する。
// if(buf.startsWith("d")){
// <ディレクトリとしての処理>
// }
//のように。
//sendLine("NLST -alL");
sendLine("LIST");
Socket dataSocket = new Socket(ip, port);
response = bufReader.readLine();
jTextAreaLog.append(response+BR);
if (!response.startsWith("150 ")) {//not Connection Accepted
throw new IOException("データリンクソケット接続ができません。: "
+ response);
}
try{
BufferedReader reader = new BufferedReader(
new InputStreamReader(dataSocket.getInputStream()));
// リストの取得
String buf;
while((buf = reader.readLine()) != null)
{
jTextAreaLog.append(buf+BR);
flist_array.add(buf);
}
// ストリームを閉じる
reader.close();
response = bufReader.readLine();
jTextAreaLog.append(response+BR);
}
catch(Exception e){
throw new IOException("ファイルリスト取得に失敗。");
}
String[] result = new String[flist_array.size()];
flist_array.toArray(result);
return result;
}
}
動作画面例

FTP in Java Sample
Kom., 2013
