【Java】環境に依らずjar内のファイルを取得する

# はじめに
例えばテキストのテンプレートを取得したい時。
開発環境と本番が違う場合(というかほぼ違うと思いますが)、絶対パスって環境依存ですよね。
環境ごとの配置場所をプロパティに書き出してもいいですが設定値は少ないほうがいいし、できればjarに含めたい。
ということで、今回はjar内のリソースを取得するユーティリティです。

# 実装

## 環境

- Windows10
- Java7
- Maven

## FileUtilクラス

```java:FileUtil.java
package jp.demo.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class FileUtil {
	private static final String CHARSET_UTF8 = "UTF-8";
	private static final String LF = "\n";

	/**
	 * 1行ずつListに詰めて返す。（改行文字除く）
	 * @param string
	 * @return
	 * @throws IOException
	 */
	public static List<String> getTextLines(String string) throws IOException {
		List<String> list = new ArrayList<>();
		try (InputStream is = ClassLoader.getSystemResourceAsStream(string);
				BufferedReader br = new BufferedReader(new InputStreamReader(is, CHARSET_UTF8))) {
			String line;
			while ((line = br.readLine()) != null) {
				list.add(line);
			}
		}
		return list;
	}

	/**
	 * Stringにして返す。（改行コードはLF）
	 * @param string
	 * @return
	 * @throws IOException
	 */
	public static String getTextStr(String string) throws IOException {
		StringBuilder sb = new StringBuilder();
		try (InputStream is = ClassLoader.getSystemResourceAsStream(string);
				BufferedReader br = new BufferedReader(new InputStreamReader(is, CHARSET_UTF8))) {
			String line;
			while ((line = br.readLine()) != null) {
				sb.append(line + LF);
			}
		}
		return sb.toString();
	}
}
```

## Mainクラス

```java:Main.java
package jp.demo;

import java.io.IOException;
import java.util.List;

import jp.demo.util.FileUtil;

public class Main {
	public static void main(String[] args) {
		System.out.println("### START ###");
		List<String> list = null;
		String str = null;
		try {
			list = FileUtil.getTextLines("jp/demo/text1.txt");
			str = FileUtil.getTextStr("jp/demo/text1.txt");
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("getTextLines:");
		list.forEach(System.out::println);
		System.out.println("\ngetTextStr:");
		System.out.println(str);

		System.out.println("### END ###");
	}
}
```

## テキストファイル
文字コード：UTF-8、改行コード：CRLF
で以下をsrc/main/resources/jp/demo/text1.txtに保存しています。

```txt:text1.txt
row1 test test
row2 あああ
row3 山田さん
```

# 実行
maven installしてjarを作成する。

# 実行結果
どちらのメソッドでもテキストファイルを取得できました。

```:実行結果
C:\sts\workspace\simple_maven\target>java -jar test-0.0.1-SNAPSHOT.jar
### START ###
getTextLines:
row1 test test
row2 あああ
row3 山田さん

getTextStr:
row1 test test
row2 あああ
row3 山田さん

### END ###

C:\sts\workspace\simple_maven\target>
```

文字コードSJISでテキストを保存した場合はこうなります。↓

```:実行結果
C:\sts\workspace\simple_maven\target>java -jar test-0.0.1-SNAPSHOT.jar
### START ###
getTextLines:
row1 test test
row2 ??????
row3 ?R?c????

getTextStr:
row1 test test
row2 ??????
row3 ?R?c????

### END ###

C:\sts\workspace\simple_maven\target>
```

SJISのテキストをUTF-8で読み込んだので文字化けしましたね。
それから、SJISに存在しない文字(有名なのは髙橋の「髙」など)を文字セットSJISでファイル出力したときも「?」に置き変わります。

## 余談
Eclipse上だと、Mavenプロジェクトはsrc/main/**java**、src/main/**resources**
に分かれますが、ビルドしてしまえば一緒になるのでどちらにテキストを保存しても同じです。

```txt:jarを展開してjp/demo/の下を見てみる
C:\Users\xxx\Desktop\test-0.0.1-SNAPSHOT\jp\demo のディレクトリ

2019/06/12  00:57    <DIR>          .
2019/06/12  00:57    <DIR>          ..
2019/06/12  00:27             1,815 Main.class
2019/06/11  01:39                26 text1.txt
2019/06/12  00:57    <DIR>          util
```