Writing /volume1/Web/Public/dokuwiki/data/log/deprecated/2024-11-14.log failed
Writing /volume1/Web/Public/dokuwiki/data/log/deprecated/2024-11-14.log failed

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

1)
CR:Carriage Return, LF:Line Feed
2)
excelデータインポート機能を利用してcsvを開く場合、改行文字で改行されてしまうので、問題になる。 しかし、ダブルクリックで開く場合は、改行文字をダブルクオーテーション(“)で囲むと問題ない。

コメント

コメントを入力. Wiki文法が有効です:
Q S I H P
 

QR Code
QR Code study:java:csv (generated for current page)