- PR -

jspからftpサーバにアップロード

投稿者投稿内容
たかひと
常連さん
会議室デビュー日: 2007/07/06
投稿数: 21
投稿日時: 2007-07-06 19:49
 クライアント(jsp)からftpサーバにファイルをアップロードさせようとしているのですが、具体的にどのようにしたらよいのかわかりません。

 今jsp側ではformで「enctype="multipart/form-data"」とし、servlet側では
「org.apache.commons.fileupload」を使用しているのですが、そこから
「java.net.Socket」類を使おうとしたところでわからなくなりました。

 ネットで検索して、いろいろなソースを参考にそれらをつなぎ合わせているのですが
思うようにいきません。

 ご教授、宜しくお願いします。

山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2007-07-06 21:26
「jspからftpサーバにアップロード する方法」がわからないのでしょうか?
であれば「servletからftpサーバにアップロード する方法」と同じです。スクリプトレット内でそのまま応用できます。

「servletからftpサーバにアップロード する方法」もわからないのだとすれば
「javaアプリケーションからftpサーバにアップロードする方法」と同じです。putメソッド内でそのまま応用できます。

「javaアプリケーションからftpサーバにアップロードする方法」がわからないのだとすれば Jakarta Commons-Net を利用するのが手っ取り早いと思います。
http://jakarta.apache.org/commons/net/


クライアント(jsp)というのが少々ややこしいですが、ftpサーバにアップロードしたいのはブラウザからアップロードされたファイルを受け取ったサーバサイドですよね?
jsp は通常クライアントサイドでは動かしませんので、クライアントからftpサーバにアップロードしたいのであれば ftp コマンドとか、ffftp とか、CyberDuck とかを使うのが良いと思います。
たかひと
常連さん
会議室デビュー日: 2007/07/06
投稿数: 21
投稿日時: 2007-07-08 00:42
返信が遅れて大変申し訳ありません。

>ftpサーバにアップロードしたいのはブラウザからアップロードされたファイルを受け取ったサーバサイドですよね?

 わかりにくい表記をしてしまいすみません。おっしゃられるとおりブラウザからファイルを受け取り、そのファイルをftpサーバにアップロードさせたいということです。
javaアプリケーションでアップロードさせたときはストリーム系を使ってアップできたのでそれを利用してブラウザからアップロードしようと試したところ、きちんと取得できなかった次第です。

 一度、教えていただいたCommons-Netを使って試して見たいと思います。

 ありがとうございました。
たかひと
常連さん
会議室デビュー日: 2007/07/06
投稿数: 21
投稿日時: 2007-07-09 14:11
Commons-Netを使う前に、基本的なことを理解しようと下記のように作成してみました。
(多数のサイトを参考に合わせただけですが)

////////////////////////////////////////////////////////////////////
public class UpLoad extends HttpServlet{

private static final long serialVersionUID = 1L;

final static String FILE_NAME_STRING = "filename=";
final static String CONTENT_TYPE_HEADER="Content-Type: ";

private static final int CTRLPORT = 21; // ftpの制御用のポート
private static Socket ctrlSocket; // 制御用ソケット
private static PrintWriter ctrlOutput; // 制御出力用ストリーム
private static BufferedReader ctrlInput; // 制御入力用ストリーム
private static byte[] localHostAddress; // ローカルホストのアドレス

public void doPost(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException {

HttpSession session = req.getSession();
ServletContext sc = session.getServletContext();
RequestDispatcher rd = sc.getRequestDispatcher("/");

//**********************************//
// ファイルの読み込み //
//**********************************//

// 受信用バッファ
byte buffer[] = new byte[4096];

int size;
String header;

// 入力用ストリーム
ServletInputStream in = req.getInputStream();

// boundaryの読み込み
size = in.readLine(buffer,0,buffer.length);

// 末尾の改行(CR+LF)を除いて文字列に変換
String boundary = new String(buffer,0, size-2);

// Content-Dispositionヘッダの読み込み
size = in.readLine(buffer,0,buffer.length);
header = new String(buffer,0, size-1);

// Content-Dispositionからファイル名の取得
String fileName = header.substring(header.indexOf(FILE_NAME_STRING)+
FILE_NAME_STRING.length()+1, header.length()-2);

// フルパスのため、ファイル名のみ取り出す
File file = new File(fileName);
fileName = file.getName();

// Content-Typeヘッダの読み込み
size = in.readLine(buffer,0,buffer.length);
header = new String(buffer,0, size-1);
// String contentType = header.substring(CONTENT_TYPE_HEADER.length());

// 空行をスキップ
size = in.readLine(buffer,0,buffer.length);

// 本体の読み込み
String line;
// ByteArrayOutputStreamに読み込んだ内容を出力しておく
ByteArrayOutputStream receivedBuffer = new ByteArrayOutputStream();

while((size=in.readLine(buffer,0,buffer.length)) != -1){

line = new String(buffer,0, size);
if (line.indexOf(boundary)!=-1) {
break;
}

receivedBuffer.write(buffer,0,size);
}
in.close();

//**********************************//
// ファイルの保存   //
//**********************************//

// FTPサーバ設定
String host = "***.***.***.***";
String loginName = "**********";
String password = "**********";
String dirName = "/";


// 接続
ctrlSocket = new Socket(host, CTRLPORT);
localHostAddress = ctrlSocket.getLocalAddress().getAddress();
ctrlOutput = new PrintWriter(ctrlSocket.getOutputStream());
ctrlInput = new BufferedReader(new InputStreamReader(ctrlSocket.getInputStream()));

// 承認
ctrlOutput.println("USER " + loginName);
ctrlOutput.flush();
ctrlOutput.println("PASS " + password);
ctrlOutput.flush();

// 指定したディレクトリへ移動
ctrlOutput.println("CWD " + dirName);
ctrlOutput.flush();
// バイナリモードの設定(アスキーモードの場合は'TYPE A')
ctrlOutput.println("TYPE I");
ctrlOutput.flush();


// アップロード
Socket dataSocket = dataConnection("STOR " + fileName);
OutputStream fos = dataSocket.getOutputStream();
byte buff[] = receivedBuffer.toByteArray();
// boundaryの前に出力される空行(CR+LF)を削って出力
fos.write(buff, 0, buff.length-2);

dataSocket.close();
fos.close();

// 接続を閉じます
ctrlOutput.close();
ctrlInput.close();
ctrlSocket.close();


rd = sc.getRequestDispatcher("/login.jsp");
rd.forward(req, res);


}


/**
* データ送受信用ソケットを取得します
*/
private static Socket dataConnection(String ctrlcmd)
throws IOException,UnknownHostException {
String cmd = "PORT ";
ServerSocket serverDataSocket = new ServerSocket(0,1);
for (int i=0;i<4;i++) {
cmd = cmd + (localHostAddress[i] & 0xff) + ",";
}
cmd = cmd + (((serverDataSocket.getLocalPort())/256) & 0xff)
+ ","
+ (serverDataSocket.getLocalPort() & 0xff);

ctrlOutput.println(cmd);
ctrlOutput.flush();
ctrlOutput.println(ctrlcmd);
ctrlOutput.flush();

Socket dataSocket = serverDataSocket.accept();
serverDataSocket.close();
return dataSocket;
}
}
////////////////////////////////////////////////////////////////////

これだと、テキストファイルはきちんとアップロードできるのですが、
ほかの拡張子のファイルは壊れてしまいます。
ファイルのサイズもほとんどないに等しい状態です。

どのあたりが原因で、どのように対処したらよいのでしょうか。

宜しくお願いいたします。
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2007-07-09 14:24
>javaアプリケーションでアップロードさせたときはストリーム系を使ってアップできたのでそれを利用してブラ
>ウザからアップロードしようと試したところ、きちんと取得で
スタンドアロンのアプリケーションでも、Servlet内でも、やり方は変わらないはずです。
スタンドアロンで上手くいっているのであれば Servlet に移植する際に何か間違えているはずですので、何処に違いがあるか比べてみましょう。
たかひと
常連さん
会議室デビュー日: 2007/07/06
投稿数: 21
投稿日時: 2007-07-09 17:29
ご指摘どおり、ソースを見比べてみました。
javaアプリケーションでアップロードさせたときはそのままファイルをFileInputStreamで読み込んで
////////////////////////////////////////////////////////////////////////
//  アップロードします
FileInputStream fis = new FileInputStream("***.pdf");
Socket dataSocket = dataConnection("STOR " + fileName);
OutputStream outstr = dataSocket.getOutputStream();
int n;
byte[] buff = new byte[1024];
while ((n = fis.read(buff)) > 0) {
outstr.write(buff,0,n);
}
///////////////////////////////////////////////////////////////////////////
として出来ていたので、ファイルのサイズ的に全て送信していないと考え、
///////////////////////////////////////////////////////////////////////////
// アップロード
Socket dataSocket = dataConnection("STOR " + fileName);
OutputStream os = dataSocket.getOutputStream();
ByteArrayInputStream bayi = new ByteArrayInputStream(receivedBuffer.toByteArray());
int n;
byte[] buff = new byte[4096];
while ((n = bayi.read(buff)) > 0) {
os.write(buff,0,n);
}
//////////////////////////////////////////////////////////////////////
としたら、pdfファイルはきちんと見られたました。
ただ、改行文を引いていないのでファイルサイズ的に2バイト増加してしまいます。
テキストファイルもやはり、最後に改行が入ってしまいます。
2バイト分をどこで削ればいいのか、わかりません。

どうしたら良いのか教えていただけないでしょうか。
宜しくお願いします。
たかひと
常連さん
会議室デビュー日: 2007/07/06
投稿数: 21
投稿日時: 2007-07-09 20:32
結局私なりに考えたのですが、アップロード部分を
///////////////////////////////////////////////////////////////////////
while ((n = bayi.read(buff)) > 0) {

if(n == 4096){
os.write(buff,0,n);
}
else{
os.write(buff,0,n-2);
}

}
//////////////////////////////////////////////////////////////////////////
のように変えたところ、同じサイズで転送することが出来ました。

次はCommons-Netでやってみたいと思います。
インギさん、大変ありがとうございました。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-07-09 21:15
このコードだと1/4096の確率でファイルサイズが変わりますね。
ファイルサイズが偶然4096の倍数の場合に失敗しますよ。

そもそもその改行はどこから来るか考えましたか?
println()で入っているのでしょう?
コード:
for (int i=0; i<100; i++) {
  if (i>0) {
    // 最初の行でなければまず改行する
    out.println();
  }
  // 実際の書き出し処理
  ...
  // 最後の行は改行をつけない
  out.print(...);
}


みたいなロジックにしては?

スキルアップ/キャリアアップ(JOB@IT)