目次
Introduction
CSV(comma-separated variables)はデータをカンマ(“,”)で区切って並べたファイル形式で
主に表計算ソフトやデータベースソフトがデータを保存する時に使うformatである。
汎用性が高く、多くの電子手帳やワープロソフトなどでも利用できるため、異なる種類のアプリケーションソフト間の
データ交換に使われることも多い。
実体はテキストファイルであるため、テキストエディタやワープロなどで開いて直接編集することも可能。
今回はJavaでCSV形式を書き出す方法を紹介する。
~~META: title=How to write out a list of data with a CSV format ~~
CSV Specification
you can review an original version from specification
CSV file -------- file ::= [ header ] { line } header ::= [ { entry separator } entry ] newline line ::= [ { entry separator } entry ] newline entry ::= character+ | { character* " separator " } | " entry newline entry " newline ::= \n separator ::= , character ::= a|b|..|A|B|..|0|1|.. escapedQuote ::= ""
Text Output
まずはCSV形式に合う文字列を書き出すことだが、便宜のため書き出す項目がリストに入っていると想定しよう。
項目が入るリストと列を格納するリストが必要となる。リストの中にリストが入っているイメージだ。
ロジックは意外と簡単だ。リストの項目を順番ごとにStringBufferに追加していきながらカンマをくっつけることだ。
リストの最後の項目にあったらカンマを削って改行文字を入れ替えれば良い。
ソースコードを次に示す。
public static String getCsvOutputString(ArrayList list) throws UnsupportedEncodingException { StringBuffer _sb = new StringBuffer(); Iterator _iterator = list.iterator(); if(list == null) return ""; if(list.size() == 0) return ""; while(_iterator.hasNext()) { ArrayList _line = (ArrayList) _iterator.next(); Iterator _lineIterator = _line.iterator(); while(_lineIterator.hasNext()) { String _data = (String) _lineIterator.next(); if(_data != null) { _sb.append(_data); } _sb.append(","); } //,を削って改行文字を挿入する if(_sb.length() > 0) { if(_sb.substring(_sb.length() - 1).equals(",")) { _sb.deleteCharAt(_sb.length() - 1); _sb.append(System.getProperty("line.separator")); } } } System.out.println(_sb.toString()); return _sb.toString(); }
Set Response Header
CSVファイルで出力するにはブラウザにファイルの形式や名前、容量などを知らせる必要がある。
response.setContentType("application/octet-stream;charset=UTF8"); response.setHeader("Content-Disposition", "attachment; filename="+ filename));
filenameはダウンロードする際のファイル名を指定する。
Write out to output stream
HttpServletResponseからOutputStreamを取得してこのストリムに
前のリストから作り出した文字列を出力する。
この際、文字のEncodingを指定できる。仮に日本語を出力する場合、UTF-8では文字化けてしまうので
”SJIS”で指定しなければならない。
複数の言語が混じっていたら最善の選択はUTF-8だと思うがテストして見なかったのでここはパス
try{ OutputStream _os = response.getOutputStream(); OutputStreamWriter _out = new OutputStreamWriter(_os, "UTF-8"); BufferedWriter _bout = new BufferedWriter(_out); _bout.write(outputText); _bout.close(); _out.close(); }catch(IOException ioe){ //handle exception }
Issue
CSVの仕様上、カンマで区切る為、もしカンマが含まれていたら不具合が発生する。
また、列の最後に改行文字(CR-LF)1)が入れる為、もし改行文字が入っている場合、問題になることがある。2)
そこで、この問題に対応するTipを紹介したいと思う。
カンマ(,)に関してはCSVの仕様(specification)でダブルクオーテーション(”)で囲むようになっている。
改行文字の場合はCR-LF(\r\n)ではなくLF(\n)を使うことを奨励している。
(Comma-separated_valuesに行けばこれらの例が載っている。)
以上二つの点を踏まえて対応する方法がこれだ。
public static String escapeCsvStr(String string) { String _ret = getNullString(string); StringBuffer temp = new StringBuffer(); if(!"".equals(_ret)) { temp.append("\"").append(_ret).append("\""); //改行文字の削除 _ret = temp.toString(); _ret = _ret.replaceAll("\r\n", "\n"); } return _ret; }
リストの項目全体をダブルクォーテーション(“)囲んで中のCR-LFをLFで入れ替える処理だ。
Reference
- http://supercsv.sourceforge.net/csvSpecification.html : CSV Specification
コメント