Apache Commons CSVによるCSV出力

# はじめに
CSVを出力するのはさほど難しいことではないが、一応いくつか仕様のようなものがあり、知らずに出力すると仕様を無視したものが出来上がってしまうことがあり得る。というか近いことをやりかけたことがある。
仕様自体は[wiki](https://ja.wikipedia.org/wiki/Comma-Separated_Values)でも[公式仕様](https://tools.ietf.org/html/rfc4180)でも確認すればよいが、JavaはApacheがCSVを読み書きするためのライブラリを公開していたりするので、こちらを使った出力についてまとめた。読み込みはやらない。

# 公式マニュアル
## 基本
http://commons.apache.org/proper/commons-csv/

## Javadoc
http://commons.apache.org/proper/commons-csv/apidocs/index.html

# 初期設定について
https://mvnrepository.com/artifact/org.apache.commons/commons-csv
MavenやGradleを使う場合は上記を参考にしてgroupId等を取得すればよい。
一応公式が[ダウンロードリンク](http://commons.apache.org/proper/commons-csv/download_csv.cgi)を公開していたりもするので、こちらからダウンロードして動かすこともできるはず（未確認）。

# 基本的な使い方
JavadocのCSVPrinterのところに[簡単な例](http://commons.apache.org/proper/commons-csv/apidocs/index.html)が記述してある。

```java:記述例
try (CSVPrinter printer = new CSVPrinter(new FileWriter("csv.txt"), CSVFormat.EXCEL)) {
    printer.printRecord("id", "userName", "firstName", "lastName", "birthday");
    printer.printRecord(1, "john73", "John", "Doe", LocalDate.of(1973, 9, 15));
    printer.println();
    printer.printRecord(2, "mary", "Mary", "Meyer", LocalDate.of(1985, 3, 29));
} catch (IOException ex) {
    ex.printStackTrace();
}
```

```:出力例
id,userName,firstName,lastName,birthday
1,john73,John,Doe,1973-09-15

2,mary,Mary,Meyer,1985-03-29
```

以下解説。

```java
CSVPrinter printer = new CSVPrinter(new FileWriter("csv.txt"), CSVFormat.EXCEL)
```

`CSVPrinter`がCSV出力用のインスタンス。`CSVFormat.EXCEL`がCSV出力時の形式である。基本的にはRFC4180をベースにした[DEFAULT](http://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVFormat.html#DEFAULT)（ただし若干違いあり）やEXCELファイルの仕様に沿った[EXCEL](http://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVFormat.html#EXCEL)を使えばよいと思うが、一応ほかにも色々あるので[公式のJavadoc](http://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVFormat.html)を確認してみるのが良い。
それぞれの違いもJavadocを確認すればわかるが、一部CSVの読み込みにしか関係しない設定もある。

```java
printer.printRecord("id", "userName", "firstName", "lastName", "birthday");
printer.printRecord(1, "john73", "John", "Doe", LocalDate.of(1973, 9, 15));
printer.println();
printer.printRecord(2, "mary", "Mary", "Meyer", LocalDate.of(1985, 3, 29));
```
`printRecord`で１行分のデータが出力される。引数は`Object`なので文字列以外も受け取れる。`println`で改行。
なお値の中に区切り文字が含まれていれば、形式に沿った形で出力される（`CSVFormat.EXCEL`なら値が`"`で囲まれた状態で出力される）。

```java:値に区切り文字
printer.printRecord("te,st", "テスト");
```

```:値に区切り文字ありの場合の出力例
"te,st",テスト
```

# その他の使い方について
## 出力
[printメソッド](http://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVPrinter.html#print-java.lang.Object-)を使うことで、１レコードごとではなく１つの値ごとに出力することができる。連続して実行すれば自動で区切り文字を入れてくれるが、同じ行の中で`printRecord`メソッドと同時に使おうとしても区切り文字は入れてくれない。

```java:printとprintRecordの併用
printer.print("test1");
printer.print("test2");
printer.printRecord("test3", "test4");
```

```:出力
test1,test2test3,test4
```

その他コメントを出力する[printCommentメソッド](http://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVPrinter.html#printComment-java.lang.String-)や、１レコードではなく複数行を出力する[printRecordsメソッド](http://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVPrinter.html#printRecords-java.lang.Object...-)なんかもある（`printRecords`にいたっては[ResultSet](https://docs.oracle.com/javase/jp/8/docs/api/java/sql/ResultSet.html)を引数に取れたりする）ので、必要に応じて使い分けるのがよいだろう。

## CSV形式
`CSVFormat`の使い方によっては、あらかじめCSVの形式に手を加えることができる。下記の例では、あらかじめヘッダー行を追加し、区切り文字をタブ文字に変更している。

```java:CSV形式修正
CSVPrinter printer =
    CSVFormat.DEFAULT.withHeader("ヘッダー1", "ヘッダー2", "ヘッダー3").withDelimiter('\t').print(writer);
printer.printRecord("a", "b", "c");
```

```:出力例
ヘッダー1	ヘッダー2	ヘッダー3
a	b	c
```

`withHeader`メソッドでヘッダー行を追加し、`withDelimiter`メソッドで区切り文字を変更している。最後の`print`メソッドは`CSVPrinter`のインスタンスを取得するためのもの。
ほかにも色々あるのでこれらを使うことで作成するCSVの形式をいろいろいじれるようになるが、よくわからないCSVを作成することでほかのアプリケーションからCSVとして読み込まれないようになるなんてことはないようにしたい。

# おわりに
標準機能でCSV扱いたい。