Javaでcsvファイルを読む

## 前置き
「最近暑すぎる...」

自宅で勉強しようとしても
（母）「電気代がもったいないっでしょ！」
と言われ、汗だらだらで勉強しる田舎者SEです。

今日はJava Goldの資格勉強もかねて
「csvファイルからデータを読みこんでコンソールに出力する」というのをやってみたいと思います。
使用するCSVデータは気象庁の過去の気象データです。
データを取得する部分から一緒にやってみりん！

##1 ①「気象庁のサイトでデータを取得するぞー！」
まずは、下記のリンクから気象庁のサイトに入ってください。

https://www.data.jma.go.jp/gmd/risk/obsdl/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484672/559e5740-b6ff-cda8-8aa5-80869b3ff018.png)

この画面で自分のお好みの条件を指定して「CSVファイルをダウンロード」ボタンを押したらCSVがダウンロードできます。

今回私は以下のように設定してみました。
〇地点を選ぶ
・愛知県名古屋市
・愛知県岡崎市

〇項目を選ぶ
・日平均気温
・日最高気温
・日最低気温
・降水量の日合計

〇期間を選ぶ
2023年4月16日から2023年7月16日までの日別値を表示

〇表示オプションを選ぶ
利用上注意が必要なデータの扱い→値を表示（格納）しない。
観測環境などの変化の前後で値が不均質となったデータの扱い→観測環境などの変化前の値を表示（格納）しない。

今回はＣＳＶファイルを読み書きすることだけをやりたいので表示オプションはすべて表示しないようにし、
余計な列は最初から減らしておきます。

## ②ダウンロードしたファイルを確認
メモ帳で開くとこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484672/ff81e835-0c8f-e3f1-5070-be0a1abfa86d.png)

表計算ソフト（主はExcel持っていない貧乏人なのでLibraOfficeです(´;ω;｀)）で開くとこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484672/31347e3c-d46d-5d6a-b816-25ef465e38af.png)

１行目がダウンロードした日付、
３行目に地点情報、
４行目に各列名、
７行目からデータが格納されているという構成のようです。

## ③ひとまず、そのまま読み込んで出力できるか試してみよう
java.util.Scannerクラスを使えば、文字入力ストリームを簡単に使えるようです。
```java
//Mainクラス
public class Main {
	public static void main(String[] args) throws Exception {
		//ファイルから読み込むFIleInputStreamのインスタンスを作り、それをScannerクラスに渡す
		FileInputStream fis = new FileInputStream("C:\\Users\\user\\Documents\\study\\data.csv");
		Scanner scanner = new Scanner(fis);

		try (scanner) {
			while (scanner.hasNext()) { //次に読み込むべき行があるか判定
				System.out.println(scanner.next()); //nextメソッドで1行ずつ読み込んでコンソールに出力
			}
		}
    }
}
```
もしかしたら、次のような疑問が出た方もいるかもしれません。（主は出ました...笑）
疑問①　最初からScannerクラスにファイルパタス渡したらダメなの？
→あくまで、Scannerクラスは文字入力ストリームを簡単にしたもの。
 もし、Scannerクラスにファイルパスを文字列で渡してもそのままファイルパスが１行コンソールに出力されて終わりです(笑)
　「ファイルから文字を読み込んでいるのはFileInputStreamってことだら！」

疑問②　なんでtry文つけてるの？
→「try-with-resources文」ってやつじゃんね。
  Javaでは通常プログラムで外部との接続を行う時、そのオブジェクト（接続）を閉じ（解放）なければならないらしい。
　普通はtry-catch-finallyでfinallyにcloseメソッドを記述するんだけど、
 「try-with-resources文」では、tryブロックの中で利用したオブジェクトをtryブロックが終了した時に自動的にcloseするという
  処理を行ってくれるから、finally句でわざわざ記述する必要がないらしいそ！

「疑問が出たということは、学びがあったということだ！」
「悪くないだろう..（ペコパ）」

時を戻して実行結果を確認するぞ！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484672/a8f66bcb-5ac5-64b8-be1f-9bd6372abad1.png)

「お！ちゃんと出力されてる！...けどなんか文字化けしてるな」

ということで次は文字化けを直していきたいと思います。

## ④文字コードを指定するぞー！
csvファイルを開いてみると文字コードに「ANSI」と書いてありました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484672/a1b63876-e4c1-d296-bd0c-9d139174477e.png)

#### ANSIってなに？
ざっくりいうと以下のようなことらしいです。
>ANSIはShift-JISという符号化方式です。ANSIは文字集合（文字の集まり）としてJIS0208集合にのみ対応しています。よって、JIS0208以外の文字を入力してANSIで保存すると文字化けを起こします。

参考：http://office-qa.com/win/win309.htm#:~:text=ANSI%E3%81%AFShift%2DJIS%E3%81%A8%E3%81%84%E3%81%86,%E6%96%87%E5%AD%97%E5%8C%96%E3%81%91%E3%82%92%E8%B5%B7%E3%81%93%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

「Shift-JISを指定して読み込めばいいんだら？」

#### 文字コードを指定して読み込んでみる
文字コードを指定して読み込む手順は、
1. FileInputStreamをインスタンス化してcsvを読み取る
2. InputStreamReaderに渡して"Shift-JIS"で読み込む
3. 更にBufferedReaderに渡す

```java
public class Main {
	public static void main(String[] args) throws Exception {
		//csvファイルを読み込む
		FileInputStream fis = new FileInputStream("C:\\Users\\user\\Documents\\study\\data.csv");

		try {
			//Shit-JISで読み込む
			BufferedReader b_reader = new BufferedReader(new InputStreamReader(fis, "Shift-JIS"));
			try (Scanner scanner = new Scanner(b_reader)) {
				while (scanner.hasNext()) { //次に読み込むべき行があるか判定
					System.out.println(scanner.next()); //nextメソッドで1行ずつ読み込んでコンソールに出力
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}
}
```


「はいはい、わかってるよ！ なんで「3.更にBufferdReaderに渡す」だら？」
これも調べ始めると深みにハマりそうなので割愛しますが、こうすることによって処理を速度を向上できるようです。

詳しくは知りたい人はこのサイトが参考になるかも
https://rainbow-engine.com/compare-inputstream-bufferedreader/

#### 「時を戻そう！！（ぺこぱ）」
以下、処理結果です。文字化けが解消されてるのが確認できました！やったー！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484672/9d43a00a-f262-509e-7032-e4c87300f662.png)

Java Goldの資格勉強としての範囲は以上だよ。

## ⑤最高＆最低気温を取得してみよう！
「CSVファイルを画面に出力するだけっていつ使うんだよ...」

ということで、最高気温を取得してコンソール出力する処理を今の知識で作ってみたぞ！
↑次回投稿予定