ファイルの保存

広告

ではいよいよクライアントから送られてきたファイルをサーバ側に保存してみます。前のページで見たとおり送られてきたデータの各パーツはFileItemインターフェースのオブジェクトとして取り出すことができます。そこでまずインターフェースについて見てみましょう。

org.apache.commons.fileupload 
Interface FileItem

public interface FileItem extends java.io.Serializable

では使い方を詳しく見ていきます。

アップロードされたファイルかそうではないのかの判別

クライアントからフォーム経由で送られ来るものは、アップロードしたいファイルだけではなく、フォームの他のコントロール(テキストやチェックボックス)のデータなども送られてきます。FileItemオブジェクトとして取得できるものは、ファイルだけではなくテキストコントールに入力されたテキストということもあるわけです。

そこでまずFileItemオブジェクトの中で、ファイルが添付されたものだけを選ぶようにします。このためにはFileItemインターフェースで定義されている"isFormField"メソッドを使います。

Determines whether or not a FileItem instance represents a simple 
form field. 

Returns:
  true if the instance represents a simple form field; false if it
    represents an uploaded file.

もし該当のFileItemオブジェクトが、アップロードされたファイルで無ければTrueを返します。この場合はフォームの他のコントロールで入力されたデータと言うわけです。

例えば下記のようになります。

DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload sfu = new ServletFileUpload(factory);

try {
  List list = sfu.parseRequest(request);
  Iterator iterator = list.iterator();

  while(iterator.hasNext()){
    FileItem item = (FileItem)iterator.next();

    if (!item.isFormField()){
      // アップロードされたファイルのみ対象の処理
    }
  }
}catch (FileUploadException e) {
  e.printStackTrace();
}

ファイルの名前の取得

前のサンプルでも使いましたが、アップロードされたファイルのファイル名を取得するにはFileItemインターフェースで定義されている"getName"メソッドを使います。アップロードされたファイルをサーバ側に保存する場合に、元のファイル名をそのまま使って保存する場合があると思います。その為にファイル名を取り出します。

Returns the original filename in the client's filesystem, as provided
by the browser (or other client software). In most cases, this will be
the base file name, without path information. However, some clients, 
such as the Opera browser, do include path information. 

Returns:
  The original filename in the client's filesystem.

前のサンプルでは単にファイル名を取り出していましたが、ファイル名が定義されていなかったり、空白でない事を確認した上で処理しておきましょう。

DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload sfu = new ServletFileUpload(factory);

try {
  List list = sfu.parseRequest(request);
  Iterator iterator = list.iterator();

  while(iterator.hasNext()){
    FileItem item = (FileItem)iterator.next();

    if (!item.isFormField()){
      String filename = item.getName();

      if ((filename != null) && (!filename.equals(""))){
        // ファイル名に関する処理
      }
    }
  }
}catch (FileUploadException e) {
  e.printStackTrace();
}

注意するのは、取り出せるファイル名はファイル名だけの場合もあるし、アップロードされたファイルのパス情報まで含めて取得する場合もあります。アップロードされたファイルが元々あったパス名が分かっても仕方無いので、ファイル名だけを取り出しておきます。その為には、いったんFileクラスのオブジェクトを作成し、そしてファイル名だけを取り出します。

DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload sfu = new ServletFileUpload(factory);

try {
  List list = sfu.parseRequest(request);
  Iterator iterator = list.iterator();

  while(iterator.hasNext()){
    FileItem item = (FileItem)iterator.next();

    if (!item.isFormField()){
      String filename = item.getName();

      if ((filename != null) && (!filename.equals(""))){
        // ファイル名に関する処理
        filename = (new File(filename)).getName();
      }
    }
  }
}catch (FileUploadException e) {
  e.printStackTrace();
}

これでファイル名だけを取り出す事が出来ました。

ファイルの保存

ではいよいよファイルを保存します。ファイルを保存するにはFileItemインターフェースで定義されている"write"メソッドを使います。

A convenience method to write an uploaded item to disk. The client 
code is not concerned with whether or not the item is stored in 
memory, or on disk in a temporary location. They just want to write
the uploaded item to a file. 

This method is not guaranteed to succeed if called more than once
for the same item. This allows a particular implementation to use, 
for example, file renaming, where possible, rather than copying all
of the underlying data, thus gaining a significant performance benefit. 

Parameters:
  file - The File into which the uploaded item should be stored. 
Throws: 
  java.lang.Exception - if an error occurs.

保存先を表すファイルクラスのオブジェクト引数に指定して"write"メソッドを実行すると、FileItemオブジェクトに格納されているデータを保存することができます。

今回保存するディレクトリを「d:¥servlet-sample¥upload¥data」というディレクトリに保存することにしてみましょう。

String path = getServletContext().getRealPath("data");

DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload sfu = new ServletFileUpload(factory);

try {
  List list = sfu.parseRequest(request);
  Iterator iterator = list.iterator();

  while(iterator.hasNext()){
    FileItem item = (FileItem)iterator.next();

    if (!item.isFormField()){
      String filename = item.getName();

      if ((filename != null) && (!filename.equals(""))){
        filename = (new File(filename)).getName();
        item.write(new File(path + "/" + filename));
      }
    }
  }
}catch (FileUploadException e) {
  e.printStackTrace();
}catch (Exception e) {
  e.printStackTrace();
}

保存先のディレクトリ名は次のように求めています。

String path = getServletContext().getRealPath("data");

これは、このWebアプリケーション上で「data」というディレクトリが実際のディレクトリ構成ではどのようになるかを取得しています。

保存してようとしているファイル名が既にある場合など細かい点は調整が必要ですが、一応これで保存できるようにはなりました。

アップロードテスト

では実際に試してみましょう。

下記を「UploadTest.java」として保存して下さい。下記はアップロードされたファイルのファイル名を表示するだけのサンプルです。

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.commons.fileupload.*;
import org.apache.commons.fileupload.servlet.*;
import org.apache.commons.fileupload.disk.*;
import java.util.List;
import java.util.Iterator;

public class UploadTest extends HttpServlet {
  public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException{

    response.setContentType("text/html; charset=Shift_JIS");
    PrintWriter out = response.getWriter();

    request.setCharacterEncoding("Shift-JIS");

    String path = getServletContext().getRealPath("data");

    out.println("<html>");
    out.println("<head>");
    out.println("<meta http-equiv=¥"Content-Type¥" content=¥"text/html;charset=Shift_JIS¥">");
    out.println("<title>Upload Test!</title>");
    out.println("</head>");
    out.println("<body>");

    DiskFileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload sfu = new ServletFileUpload(factory);

    try {
      List list = sfu.parseRequest(request);
      Iterator iterator = list.iterator();

      while(iterator.hasNext()){
        FileItem item = (FileItem)iterator.next();

        if (!item.isFormField()){
          String filename = item.getName();

          if ((filename != null) && (!filename.equals(""))){
            filename = (new File(filename)).getName();
            item.write(new File(path + "/" + filename));
          }

          out.println("<p>");
          out.println("ファイル名" + item.getName() + "を");
          out.println(path + "/" + filename + "に保存しました");
          out.println("</p>");
        }
      }
    }catch (FileUploadException e) {
      e.printStackTrace();
    }catch (Exception e) {
      e.printStackTrace();
    }

    out.println("</body>");
    out.println("</html>");
  }
}

コンパイルが終わりましたら作成されたクラスファイルを「d:¥servlet-sample¥upload¥WEB-INF¥classes¥」ディレクトリに配置します。(必要に応じてTomcatを再起動して下さい)。

ではブラウザから「http://localhost:8080/upload/uploadtest.html」と呼び出して下さい。

HTMLファイルの表示

「参照」ボタンを押してアップロードするファイルを選択します。

アップロードファイルの選択

今回は「d:¥servlet-sample¥tmp」内にある「test.txt」ファイルを選択しました。では「アップロード」ボタンをクリックします。

アップロードの結果

上記のようにアップロードされたファイルのファイル名が表示されれば成功です。実際にアップロード先のディレクトリの中身を見てみると次のようにファイルが格納されています。

アップロードの結果

( Written by Tatsuo Ikura )

関連記事 (一部広告含む)