2010/04/27

CSVファイルの読込

社内の受託案件で、以前作ったメール送信用のアプリを使いたいという要望があり、隙間の時間で少しずつカスタマイズしてます。その中で送信先のユーザー情報をCSVで一括取込したいというのがあったので、簡単にCSVを任意のBeanのListに変換するようなクラスを作ってみました。この機能はアノテーションを使うのでJava5以上が必要となります。

1. アノテーション
まずはBeanのフィールドに指定するアノテーションです。CSVを読み込んだときに、このアノテーションが宣言されているフィールドに対して、値を設定します。
  1. /** 
  2.  * CSVデータの保持対象を表すアノテーションです。 
  3.  * このアノテーションはビーンクラスのフィールドに対して宣言します。 
  4.  *  
  5.  * @author namiki 
  6.  *  
  7.  */  
  8. @Retention(RetentionPolicy.RUNTIME)  
  9. @Target(ElementType.FIELD)  
  10. @Documented  
  11. public @interface CsvColumns {  
  12.  /** 
  13.   * CSVのカラム順を指定します。 
  14.   *  
  15.   * @return カラム順 
  16.   */  
  17.  int index();  
  18. }  
indexでCSVの何カラム目を設定するか、指定します。

2. 任意のBean
続いてCSVの内容を設定するBeanです。
  1. public class Entity {  
  2.  @CsvColumns(index = 0)  
  3.  public Integer id;  
  4.   
  5.  @CsvColumns(index = 2)  
  6.  public String name;  
  7.   
  8.  @CsvColumns(index = 1)  
  9.  public String email;  
  10. }  
Seasar2には依存していませんが、基本的にSeasar2環境で使うことを想定しているため、publicフィールドを採用しています。

3. CSVParser
最後にCSVを読み込むためのクラスです。
  1. /** 
  2.  * CSVファイルを読み込み、型パラメータで指定されたクラスのリストを作成するクラスです。 
  3.  *  
  4.  * @author namiki 
  5.  *  
  6.  */  
  7. public class CsvFileParser<T> {  
  8.   
  9.     // ------------------------------------------------------------- [Constants]  
  10.   
  11.     /** CSVの区切り文字です。 */  
  12.     private static final String DELIMITER = ",";  
  13.   
  14.     // ------------------------------------------------------------ [Properties]  
  15.   
  16.     /** 読込対象ファイルです。 */  
  17.     private File target;  
  18.   
  19.     // ----------------------------------------------------------- [Constructor]  
  20.   
  21.     /** 
  22.      * コンストラクタです。 
  23.      *  
  24.      * @param target 
  25.      *            対象ファイル 
  26.      */  
  27.     public DcssCsvFileParser(File target) {  
  28.         this.target = target;  
  29.     }  
  30.   
  31.     // -------------------------------------------------------- [Public methods]  
  32.   
  33.     /** 
  34.      * CSVファイルを読込み、型パラメータで指定されたクラスのリストを返します。 
  35.      *  
  36.      * @param c 
  37.      *            型 
  38.      * @return リスト 
  39.      */  
  40.     @SuppressWarnings("unchecked")  
  41.     public List<T> readLines(Class<T> c) {  
  42.   
  43.         List<Object> list = new ArrayList<Object>();  
  44.         BufferedReader reader = null;  
  45.         try {  
  46.             reader = new BufferedReader(new FileReader(target));  
  47.             String line = null;  
  48.   
  49.             while ((line = reader.readLine()) != null) {  
  50.                 String[] array = line.split(DELIMITER);  
  51.   
  52.                 Object entity = c.newInstance();  
  53.                 Field[] fields = c.getFields();  
  54.                 for (Field field : fields) {  
  55.                     CsvColumns col = field.getAnnotation(CsvColumns.class);  
  56.                     if (null != col) {  
  57.                         if (field.getType() == Integer.class) {  
  58.                             field.set(entity, Integer  
  59.                                     .valueOf(array[col.index()]));  
  60.                         } else if (field.getType() == Long.class) {  
  61.                             field.set(entity, Long.valueOf(array[col.index()]));  
  62.                         } else {  
  63.                             field.set(entity, array[col.index()]);  
  64.                         }  
  65.                     }  
  66.                 }  
  67.                 list.add(entity);  
  68.             }  
  69.         } catch (Exception e) {  
  70.             throw new RuntimeException(e);  
  71.   
  72.         } finally {  
  73.             IOUtils.closeQuietly(reader);  
  74.         }  
  75.         return (List<T>) list;  
  76.     }  
  77. }  

4. 使い方
最後にこのクラスの使い方です。
  1. CsvFileParser<entity> parser = new CsvFileParser<entity>(file);  
  2. List<entity> list = parser.readLines(Entity.class);  
  3. </entity></entity></entity>  
GenericsやらClass指定やらが続いて、少し気持ち悪いですね…。ちょっとここら辺は直したいところですが、取り敢えずこんな感じでCSV読み込みを簡略化することができました。
ただあまりCSVの行数が多いとOutOfMemoryになってしまいそうなので注意が必要ですね。そこら辺も合わせてもう少し手を入れていこうと思います。

2010/04/23

またまた本を買う

休みの日にTVを見てたら村上春樹の「1Q84」のBook3が出版されたと大騒ぎになってました。
なんとなく騒がれてたのは知ってましたが、「1Q84」は読んでなかったのでこれを機に購入。残念ながらBook3は売り切れていましたが、Book1、Book2を読み終えた頃には買えるだろうと勝手に予測してます。
取り敢えずBook1は読了してBook2に突入していますが、読んでいるとなんとも不思議な感覚に陥ってしまいますね。思わず月を見上げたり、ソファの下を覗き込んだりしてしまいました。

あと、Amazonから「Seasar2徹底入門」が届きました。相変わらずこの方の文章は読み易く、分かり易いです。SAStrutsに関しては最近関わったプロジェクト群でよく使っていますが、まだまだ奥が深いです。自分自身この本で初めて知ったことなどもありますので、これをベースにまた社内用資料を作成していこうと思っています。