[java]CsvBeanReader, CsvBeanWriter, ParseDateを併用するには
前回、Beanによる読み込みとMapによる書き込みを取り上げましたが、元サイトのサンプルソースに手を加えての紹介、という趣旨だったので、Beanによる書き込みについては割愛しました。
なので、今回はBeanによる書き込みに焦点を当ててみましょう。
配布サイト:http://supercsv.sourceforge.net/
前回記事:[java]CSVの読み書きを快適に〜「Super CSV」ノススメ - Undead mode 忘備録
早速ですが、Bean内容を出力するmain実装をしてみると、↓のような感じになります。
ファイル名:WritingObjects.java
package write; import java.io.FileWriter; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.supercsv.io.CsvBeanWriter; import org.supercsv.io.ICsvBeanWriter; import org.supercsv.prefs.CsvPreference; import bean.UserBean; /** * SuperCSVによるCSVファイル書き込み(Bean) * @author kazuki.kido */ public class WritingObjects { public static void main(String[] args) throws Exception { // ヘッダ情報定義 String[] header = new String[]{"username", "password", "date", "zip", "town"}; List<UserBean> list = new ArrayList<UserBean>(); // 1行目データを作成 UserBean bean1 = new UserBean(); bean1.setUsername("Klaus"); bean1.setPassword("qwexyKiks"); bean1.setDate(new Date()); bean1.setZip(1111); bean1.setTown("Tokyo"); list.add(bean1); // 2行目データを作成 UserBean bean2 = new UserBean(); bean2.setUsername("Oufu"); bean2.setPassword("bobilop"); bean2.setDate(new Date()); bean2.setZip(4555); bean2.setTown("Tokyo"); list.add(bean2); ICsvBeanWriter writer = new CsvBeanWriter(new FileWriter("./data/boo.csv"), CsvPreference.EXCEL_PREFERENCE); try { // ファイルへ出力 writer.writeHeader(header); // エラーログ取得用バッファ StringBuilder errorLog = new StringBuilder(); // ファイルへ書き出し for(UserBean bean : list){ writer.write(bean, header, UserBean.processors, errorLog); if(errorLog.length() > 0){ System.err.println(errorLog); break; } } } finally { writer.close(); } } }
UserBeanについては前回作成したものを流用します。が、実はこのままだとエラーが発生してしまいます。エラーが発生する原因は、UserBean.javaの以下の部分。
ファイル名:UserBean.java
/** 各要素フォーマット定義 */ public static final CellProcessor[] processors = new CellProcessor[] { new Unique(new StrMinMax(4, 20)), // username new StrMinMax(7, 35), // password new ParseDate("dd/MM/yyyy"), // date new Optional(new ParseInt()), // zip null // town };
date要素の定義にParseDateを使用していますが、このクラスは「CSVから取得した文字列 ⇒ 引数のフォーマットとして解釈し、Date型に変換して保持する」ことを指示しています。
しかし、CsvBeanWrite.write(Object, String, CsvPreference, StringBuilder)で必要となるのは「Date型⇒引数のフォーマットで変換し、文字列として出力する」指示です。探してみても、この2つを満たすハイブリットなクラスは用意されていません。
ないんじゃ仕方ないですよね〜というわけで、作ってみました。
ファイル名:ParseDateEx.java
package cell; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import org.supercsv.cellprocessor.ParseDate; import org.supercsv.cellprocessor.ift.DateCellProcessor; import org.supercsv.exception.SuperCSVException; import org.supercsv.util.CSVContext; /** * write時の処理を考慮したParseDate拡張 * @author kazuki.kido */ public class ParseDateEx extends ParseDate{ /** 日付フォーマット */ DateFormat formatter; /** * コンストラクタ * @param s */ public ParseDateEx(String s) { super(s); formatter = new SimpleDateFormat(s); } /** * コンストラクタ * @param s * @param datecellprocessor */ public ParseDateEx(String s, DateCellProcessor datecellprocessor) { super(s, datecellprocessor); formatter = new SimpleDateFormat(s); } /** * フォーマットチェック処理 * @param obj * @param csvcontext * @throws SuperCSVException */ public Object execute(Object obj, CSVContext csvcontext) throws SuperCSVException { // 出力時処理 if(obj instanceof Date){ return formatter.format((Date)obj); } // 入力時処理 return super.execute(obj, csvcontext); } }
ParseDateを継承し、executeメソッドのみ小細工しています。他メソッドは親メソッドを呼んでいるだけです。executeメソッドの引数objにDate型が渡された場合、ファイル出力時にメソッドが呼ばれているということになるので、formatterに基づくString型の値を返します。他の型が渡された場合は親メソッドに処理を引き継ぎます。
早速これをUserBeanに適用してみます。
ファイル名:UserBean.java
package bean; import java.util.Date; import org.supercsv.cellprocessor.Optional; import org.supercsv.cellprocessor.ParseInt; import org.supercsv.cellprocessor.constraint.StrMinMax; import org.supercsv.cellprocessor.constraint.Unique; import org.supercsv.cellprocessor.ift.CellProcessor; import cell.ParseDateEx; /** * CSVファイルの要素定義(Bean) * @author kazuki.kido */ public class UserBean { /** 各要素フォーマット定義 */ public static final CellProcessor[] processors = new CellProcessor[] { new Unique(new StrMinMax(4, 20)), // username new StrMinMax(7, 35), // password new ParseDateEx("dd/MM/yyyy"), // date new Optional(new ParseInt()), // zip null // town }; /* 各要素の Getter/Setter 定義 */ private String username, password, town; private Date date; private int zip; public String getPassword() { return password; } public Date getDate() { return date; } public String getTown() { return town; } public String getUsername() { return username; } public int getZip() { return zip; } public void setPassword(String password) { this.password = password; } public void setDate(Date date) { this.date = date; } public void setTown(String town) { this.town = town; } public void setUsername(String username) { this.username = username; } public void setZip(int zip) { this.zip = zip; } }
ParseDate ⇒ ParseDateExに変わったのと、importが変更になっただけですね。
これで準備OKです。
実行してみると、以下のような内容が出力されます。
ファイル名:boo.csv
username,password,date,zip,town Klaus,qwexyKiks,30/09/2007,1111,Tokyo Oufu,bobilop,30/09/2007,4555,Tokyo
ちゃんと日付も意図した形式で出力されました。