文字コードの確認・変換・指定する方法【Java】

Javaには文字列を正しく表示するために指定する「文字コード」がある。「文字コード」の指定を間違えると、文字化けの原因になるので注意。

### 文字コードとは
文字列はプログラムの内部ではbyte型の配列の数値で表現されている。このbyte型の配列を文字列に変換して表示するときの対応関係を文字コードと言う。
よく使われる文字コードには「Shift_JIS」、「UTF-8」、「UTF-16」などがある。外部のファイルを読込む場合に、ファイルで使われている文字コードを正しく指定しないと文字化けしてしまうことがあるので注意が必要。
※Javaのデフォルトの文字コードはUnicode(UTF-16)。

文字化けした場合は次のように元の文字が分からない状態で表示されます。
```
��0B0D0F0H0J
苣膄蛣膈�
```

### デフォルトの文字コードを確認する方法
使用している開発環境のデフォルトのエンコーディングを調べるには、SystemクラスのgetPropertyメソッドを使用。
```Main.java
public class Main {
    public static void main(String[] args) {
 
        System.out.println(System.getProperty("file.encoding"));
    }
}
```
```
//実行結果
UTF-8
```
このプログラムを実行した環境では、「UTF-8」がデフォルトの文字コードであることが確認できた。

### 文字列とbyte型の配列を変換する方法
●文字コードを指定してbyte型の配列で取得する方法
文字列をbyte型の配列で取得するには、getBytesメソッドを使う。
```Main.java
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
 
public class Main {
    public static void main(String[] args) {
 
        try {
            String str = "あ";
         
            byte[] bytes1 = str.getBytes("UTF-16");
            byte[] bytes2 = str.getBytes("UTF-8");
            byte[] bytes3 = str.getBytes("SJIS");
         
            System.out.println(Arrays.toString(bytes1));
            System.out.println(Arrays.toString(bytes2));
            System.out.println(Arrays.toString(bytes3));
         
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}
```
```
//実行結果
[-2, -1, 48, 66]
[-29, -127, -126]
[-126, -96]
```
文字コードを指定して、文字列からbyte型の配列に変換することができた！ここではgetBytesメソッドに例外処理が必要なため、try-catch文を使用してい
る。
●byte型の配列をString型の文字列に変換する方法
```Main.java
new String(byte型の配列, 使用する文字コード)
```
```Main.java
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
 
public class Main {
    public static void main(String[] args) {
 
        try {
            String str = "あ";
         
            byte[] bytes1 = str.getBytes("UTF-16");
            byte[] bytes2 = str.getBytes("UTF-8");
            byte[] bytes3 = str.getBytes("SJIS");
         
            System.out.println(Arrays.toString(bytes1));
            System.out.println(Arrays.toString(bytes2));
            System.out.println(Arrays.toString(bytes3));
         
            String newStr1 = new String(bytes1, "UTF-16");
            String newStr2 = new String(bytes2, "UTF-8");
            String newStr3 = new String(bytes3, "SJIS");
         
            System.out.println(newStr1);
            System.out.println(newStr2);
            System.out.println(newStr3);
         
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}
```
```
//実行結果
[-2, -1, 48, 66]
[-29, -127, -126]
[-126, -96]
あ
あ
あ
```
byte型の配列を文字列に変換することができた！ここでは文字列をbyte型の配列に変換した後に、元の文字列に戻している。

### 文字コードを判定する方法
文字コードが正しい場合には、元の文字列と文字列に変換したbyte配列が等しくなるのでequalsメソッドで比較。

```Main.java
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
 
public class Main {
    public static void main(String[] args) {
 
        try {
            String str = "abc";
            byte[] bytes = { 97, 98, 99 };
         
            System.out.println(str.equals(new String(bytes, "UTF-16")));
            System.out.println(new String(bytes, "UTF-16"));
         
            System.out.println(str.equals(new String(bytes, "UTF-8")));
            System.out.println(new String(bytes, "UTF-8"));    
         
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}
```
```
//実行結果
false
慢�
true
abc
```
このプログラムでは文字列"abc"とbyte配列[97, 98, 99]を変換した文字列が等しくなる文字コードを調べている。
equalsメソッドの結果が"UTF-16"のときは”false”になるので、文字コードが間違っていることがわかる。
試しに"UTF-16"で文字列に変換すると文字化けをしてしまいる。
"UTF-8"のときは”true”になるので、文字コードが正しいことがわかる。変換した文字列も”abc”なので正しく変換されている！

### 文字コードを指定してファイルを読み書きする方法
●文字コードを指定してファイルを読み込む方法
TXTファイルなどの文字コードを指定して読み込むためには、InputStreamReader及びFileInputStreamクラスを拡張したBufferedReaderクラスを使用する。
引数には文字コードを指定する必要がある。
```Main.java
//
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
 
public class Main {
 
    public static void main(String[] args) {
        /* ファイルの文字コードを指定して読み込む */
        File file = new File("/Users/Shared/java/java.txt");
        try {
            BufferedReader b_reader = new BufferedReader(new InputStreamReader(new FileInputStream(file),"Shift-JIS"));
            
            /* 〜ファイル操作〜　*/
            
        } catch (UnsupportedEncodingException | FileNotFoundException e) {
            e.printStackTrace();
        }
    }
 
}
```

●文字コードを指定してファイルに書き込む方法
文字コードを指定してファイルに書き込むためには、BufferedWriter、OutputStreamWriter及びFileOutputStreamクラスを拡張した、PrintWriterクラスを使用。
引数には文字コードを指定する必要がある。
```Main.java
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
 
public class Main {
 
    public static void main(String[] args) {
        File file = new File("/Users/Shared/java/java.txt");
        
        try {
            // 文字コードを指定する
            PrintWriter p_writer = new PrintWriter(new BufferedWriter
                (new OutputStreamWriter(new FileOutputStream(file),"Shift-JIS")));
            
            //ファイルに文字列を書き込む
            p_writer.println("apple");
            p_writer.println("orange");
            p_writer.println("melon");
            
            //ファイルをクローズする
            p_writer.close();
        } catch (UnsupportedEncodingException | FileNotFoundException e) {
            e.printStackTrace();
        }
    }
 
}
```
ファイルに書き込むためには、PrintWriterクラスのprintlnメソッドを使用し、引数に文字列を指定。
PrintWriterクラスは、指定したファイルが存在しない場合は新規作成し、すでに同名のファイルが存在する場合は内容が上書きされる。

### 参考サイト
https://www.sejuku.net/blog/19673