opencsv を使ってみよう

# opencsv を使ってみよう

- 今回、会社の業務中に、AI が学習するデータを csv で入力する機能を実装する必要があり、Java で csv を操作するために使用するいくつかのライブラリの中で最もよく使われている opencsv を使ってみました。使うついでに基本的な使い方について記録しておけばいいと思い、整理してみました。
- なお、この資料はまだ完成しておらず、近いうちにサンプルコードが完全に追加される予定です。

## 目次

1. [依存性の追加](#1-依存性の追加)
2. [基本的な使い方](#2-基本的な使い方)
3. [JavaBeans と連携して使用する](#3-javabeansと連携して使用する)
4. [その他の便利な機能](#4-その他の便利な機能)
5. [まとめ](#5-まとめ)
6. [参考資料](#6-参考資料)

## 1. 依存性の追加

1. `build.gradle`に次のように opencsv の依存性を追加します [サンプルコード](https://github.com/foreverfl/study-java-opencsv/blob/main/app/build.gradle)

```groovy
dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1'

    // This dependency is used by the application.
    implementation 'com.google.guava:guava:31.1-jre'

    // https://mvnrepository.com/artifact/com.opencsv/opencsv
    implementation 'com.opencsv:opencsv:5.9'

}
```

## 2. 基本的な使い方

- opencsv を使用すると、csv ファイルを一行ずつ読むことができます。 [サンプルコード](https://github.com/foreverfl/study-java-opencsv/blob/main/app/src/main/java/study/java/opencsv/OpencsvExample.java)

```java
public class OpencsvExample {
    public static void main(String[] args) throws CsvValidationException {
        Path csvPath = Paths.get("C:\\bucket\\programming.csv");

        System.out.println("CSV File Path: " + csvPath.toAbsolutePath());
        // tryブロック内にCSVReaderを宣言し、try-with-resourcesを使用して自動的に閉じる
        try (CSVReader reader = new CSVReader(new FileReader(csvPath.toFile(), StandardCharsets.UTF_8))) {

            // ファイルを一行ずつ読むコード
            String[] line;
            while ((line = reader.readNext()) != null) {
                for (String value : line) {
                    System.out.print(value + " ");
                }
                System.out.println();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
```

## 3. JavaBeans と連携して使用する

1. opencsv は単にファイルを読むだけでなく、javabeans オブジェクトと連携して使用することができます。使用するためにはまず javabeans ファイルを作成します。私の場合は基本的に csv のカラム名でマッピングしましたが、この他にもカラム位置マッピング、ヘッダー名マッピング、アノテーションマッピングなどの様々なマッピング方式が存在します。[サンプルコード](https://github.com/foreverfl/study-java-opencsv/blob/main/app/src/main/java/study/java/opencsv/bean/Bean.java)

```java
public class Bean {
    @CsvBindByName(column = "Category")
    private String category;

    @CsvBindByName(column = "Subcategory")
    private String subcategory;

    @CsvBindByName(column = "Topic")
    private String topic;

    @CsvBindByName(column = "Question")
    private String question;

    @CsvBindByName(column = "Answer")
    private String answer;

    // Getters and setters 省略

    // toString 省略

}
```

2. このように作成した javabeans オブジェクトを`csvToBean`を介して csv 入力と連携して読み込むことができます。[サンプルコード](https://github.com/foreverfl/study-java-opencsv/blob/main/app/src/main/java/study/java/opencsv/bean/BeanExample.java)

```java
public class BeanExample {
    public static void main(String[] args) throws IOException, CsvValidationException {
        String csvPath = "C:\\bucket\\programming.csv";
        System.out.println("CSV File Path: " + Paths.get(csvPath).toAbsolutePath());

        try (CSVReader reader = new CSVReader(new FileReader(csvPath, StandardCharsets.UTF_8))) {
            CsvToBean<Bean> csvToBean = new CsvToBeanBuilder<Bean>(reader)
                    .withType(Bean.class)
                    .withIgnoreLeadingWhiteSpace(true)
                    .build();

            List<Bean> beans = csvToBean.parse();

            for (Bean bean : beans) {
                System.out.println(bean);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
```

## 4. その他の便利な機能

- `com.opencsv.bean.comparator`: このパッケージは CSV データのフィールド間の比較のための `Comparator` クラスを含みます。現在は Apache Commons Collections の `comparator` により非推奨となっています。
- `com.opencsv.bean.concurrent`: このパッケージは並列処理をサポートするクラスを含んでいます。大容量の CSV ファイルを処理する際に、性能を向上させるために並列処理を使用する際に有用です。
- `com.opencsv.bean.customconverter`: このパッケージはユーザー定義のコンバーターを定義するクラスを含んでいます。CSV データを読み書きする際に、基本提供されない特別な変換ロジックが必要な場合に有用です。
- `com.opencsv.bean.exceptionhandler`: このパッケージは CSV データを処理する際に発生する例外を処理するクラスを含んでいます。CSV 処理中に発生し得る様々な例外状況を管理したい場合に有用です。
- `com.opencsv.bean.function`: このパッケージは CSV データに対する関数型プログラミングサポートのためのクラスを含んでいます。ラムダ式や関数型インターフェースを使用して CSV データを処理したい場合に有用です。
- `com.opencsv.bean.processor`: このパッケージは CSV データを処理する様々なプロセッサを含んでいます。CSV データを読み書きする際のデータ前処理や後処理を行いたい場合に有用です。
- `com.opencsv.bean.util`: このパッケージは CSV 処理に有用なユーティリティクラスを含んでいます。CSV データ処理時に様々なユーティリティメソッドを使用したい場合に有用です。
- `com.opencsv.bean.validators`: このパッケージは CSV データの有効性検査のためのクラスを含んでいます。CSV データを読み取る前に有効性を検査してデータの整合性を保証したい場合に有用です。
- `com.opencsv.enums`: このパッケージは opencsv で使用される列挙型を含んでいます。CSV データ処理時に特定の列挙型の値を使用したい場合に有用です。
- `com.opencsv.exceptions`: このパッケージは opencsv で発生する例外を定義するクラスを含んでいます。CSV データ処理中に発生し得る特定の例外状況を具体的に扱いたい場合に有用です。
- `com.opencsv.stream.reader`: このパッケージは CSV データをストリームとして読み込むためのクラスを含んでいます。CSV データをストリーム形式で効率的に読み込む必要がある場合に有用です。

## 5. まとめ

1. Java で opencsv を使用すると簡単に、csv ファイルを作成したり読み込んだりすることができる。
2. `com.opencsv.bean`を使用すると、opencsv で読み込んだファイルを javabeans にマッピングして便利に使用することができる。マッピング方式にはいくつかの種類がある。
3. さらに、opencsv は csv で取得したデータを便利に使用するための様々なパッケージやクラスを提供している。

## 6. 参考資料

- [opencsv JavaDoc](https://javadoc.io/doc/com.opencsv/opencsv/latest/index.html)
- [Opencsv Users Guide](https://opencsv.sourceforge.net/)
- [全体サンプルコード](https://github.com/foreverfl/study-java-opencsv/tree/main)