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; } }
動作画面例
Kom., 2013