文字コードを変えて書き出す

UTF-8とShift_JIS

これまで,FileReaderでファイルを読んできました。このクラスはファイルから文字単位に読んでいくためのクラスです。ところがこれでWindowsで作られたテキストファイルを読むとうまく読むことができません。

これはLinuxとWindowsではテキストファイルの日本語の文字の保存方法に違いがあるからです。

次のようなファイルをつくり、xcode.txtという名前で保存します。

ABC。あいう

これを以前作ったDump.javaで内容を見てみます.

$ java Dump xcode.txt 
 41 42 43 e3 80 82 e3 81 82 e3 81 84 e3 81 86  a

Windowsで同じ文字を保存したファイルをDump.javaで調べてみます。

$ java Dump xcode.sjis
 41 42 43 81 42 82 a0 82 a2 82 a4  a

Shift_JISのファイルはgeditでも作れますが、xcode.sjis という名前で用意しました。Shift_JISのxcode.sjisを右クリックから一旦保存して使ってください。普通のクリックをしてしまうと環境によってはブラウザで開いてしまうかも知れません。

LINUXで作ったファイルはUTF-8という形式、WindowsではShift_JISという形式になっています。文字コードは次のようになっています。

A B C LF
UTF-8 41 42 43 e3 80 82 e3 81 82 e3 81 84 e3 81 86 a
Shift_JIS 41 42 43 81 42 82 a0 82 a2 82 a4 a

半角文字部分は共通。日本語の文字部分が異なっています。

区 点 JIS  SJIS EUC  UTF-8  UTF-16 字
04 01 2421 829F A4A1 E38181 3041   ぁ
04 02 2422 82A0 A4A2 E38182 3042   あ
04 03 2423 82A1 A4A3 E38183 3043   ぃ
04 04 2424 82A2 A4A4 E38184 3044   い
04 05 2425 82A3 A4A5 E38185 3045   ぅ
04 06 2426 82A4 A4A6 E38186 3046   う
04 07 2427 82A5 A4A7 E38187 3047   ぇ
04 08 2428 82A6 A4A8 E38188 3048   え
04 09 2429 82A7 A4A9 E38189 3049   ぉ
04 10 242A 82A8 A4AA E3818A 304A   お
04 11 242B 82A9 A4AB E3818B 304B   か
04 12 242C 82AA A4AC E3818C 304C   が
04 13 242D 82AB A4AD E3818D 304D   き
04 14 242E 82AC A4AE E3818E 304E   ぎ
04 15 242F 82AD A4AF E3818F 304F   く
04 16 2430 82AE A4B0 E38190 3050   ぐ
04 17 2431 82AF A4B1 E38191 3051   け
04 18 2432 82B0 A4B2 E38192 3052   げ
04 19 2433 82B1 A4B3 E38193 3053   こ
04 20 2434 82B2 A4B4 E38194 3054   ご
04 21 2435 82B3 A4B5 E38195 3055   さ

FileReader で読む

これをFileReaderで読んでみます。FileReaderで読み、コードポイントを表示するプログラムを作ります。各種文字コードは16進数(0,1,2,...9,a,b,c,d,e,fを使った数の表記)を使うのが一般的なので、Dumpと同じく16進数も表示するようにしています。Integer.toHexString(c)がそれです。その後10進数も書いています。

ファイル名 ShowCodePoint.java

import java.io.*;
public class ShowCodePoint { 
    public static void main( String[] args ) {
       String fname =args[0];
       try {
            FileReader   in  = new FileReader(fname);
            BufferedReader inb = new BufferedReader(in);

            int c;
            while ((c = inb.read()) != -1) {
                System.out.print( Integer.toHexString(c) );  //16進で表示
                System.out.print( " " );
                System.out.println( c );                     //10進でも表示
             }

            inb.close();
            in.close();
       }
       catch (IOException e) {
            System.err.println( "ファイルがないのでは?" );
       }
    }
}

実行結果です

$ java ShowCodePoint xcode.txt
41 65
42 66
43 67
3002 12290
3042 12354
3044 12356
3046 12358
a 10

12290は、"。"を表すコードでした。javaのコードポイントはUTF-8でもShift_JISでもありません。UTF-16というものです。

Shift_JISのファイルを読み込むと次のようになります。

$ java ShowCodePoint xcode.sjis
41 65
42 66
43 67
fffd 65533
42 66
fffd 65533
fffd 65533
fffd 65533
fffd 65533
fffd 65533
fffd 65533
a 10

これは正しく読めていません。

ではFileReaderはUTF-8で書かれたファイルを読むように作られているのでしょうか。いいえ違います。Windows環境ではShift_JISのファイルが正常に読め、UTF-8のファイルは正常に読めなくなります。

つまり、FileReaderはOSの標準の文字コードで書かれているファイルを読むように設計されているのです。

javaはコンパイルされたプログラム(classファイル)はLinux環境でもWindows環境でもコンパイルし直さなくても実行できます。ですからそれぞれの環境で使っている文字コードをそのまま使うように設計されていた方が便利だからです。

LinuxでShift_JISファイルを読む

FileReaderはOSの標準(デフォルト)の文字コードで読むクラスです。他の文字コードで読むにはまず、FileInputStream でバイト毎に読んで、InputStreamReader で文字コードを指定して文字に組み立てていきます。

ファイル名 ShowCodePointS.java

import java.io.*;
public class ShowCodePointS { 
    public static void main( String[] args ) {
       String fname =args[0];
       try {
            FileInputStream is  = new FileInputStream(fname);
            InputStreamReader in = new InputStreamReader(is,"Shift_JIS");
            //FileReader   in  = new FileReader(fname);
            BufferedReader inb = new BufferedReader(in);
            int c;
            while ((c = inb.read()) != -1) {
                System.out.print( Integer.toHexString(c) );
                System.out.print( " " );
                System.out.println( c );
 
             }
            inb.close();
            in.close();
       }
       catch (IOException e) {
            System.err.println( "ファイルがないのでは?" );
       }
    }
}

これでShift_JISのファイルが読めます。

$ java ShowCodePointS xcode.sjis
41 65
42 66
43 67
3002 12290
3042 12354
3044 12356
3046 12358
a 10

その代わりUTF-8が読めなくなりました。

$ java ShowCodePointS xcode.txt
41 65
42 66
43 67
7e32 32306
3085 12421
2260 8800
7e3a 32314
fffd 65533
2267 8807
a 10

(この状況はWindows上でFileResderで読む時の状態と全く同じです)

InputStreamReader は、バイトデータの並びを読み込んで、指定された文字セットを使用して文字に変換します。文字セットの指定が省略されると、javaのデフォルトの文字セットに変換します。

つまり、文字セットの指定が省略されるとFileReaderと同じ機能になります。

ファイルを読んで文字コードを変えて書き出す

OutputStreamWriter は指定された文字セットに変換し、バイトデータの並びとして書き出します。

次のプログラムはUTF-8でかかれたxcode00.txtというファイルから読み込み、EUC-JPに変換してxcode01.txtに書きます。

ファイル名 Xcode.java

import java.io.*;

public class Xcode {
     public Xcode(String ifname, String ofname){
        try {
            FileInputStream in  = new FileInputStream(ifname);
            InputStreamReader inx = new InputStreamReader(in,"UTF-8");
            FileOutputStream out = new FileOutputStream(ofname);
            OutputStreamWriter outx = new OutputStreamWriter(out,"EUC-JP");

            //読み込みと書き込み
            int c;
            int ct = 0;
            while ((c = inx.read()) != -1) {
                outx.write(c);
                ct++;
            }
            System.out.println("以上" + ct + "文字");
            
            inx.close();
            in.close();
            outx.close();
            out.close();
        } catch (IOException e) {
            System.out.println( ifname + " がないのでは?" );
        }
    }
    public static void main(String[] args) {
        Xcode x = new Xcode("xcode00.txt","xcode01.txt");
    }
}

他の文字コードを使いたい時は下の表を参考にしてください。ただし、最初の2つISO-8859-1とUS-ASCIIは日本語に対応しません。

java.nioでの名前 java.ioでの名前
これを使用
説明
ISO-8859-1 ISO8859_1ISO 8859-1, Latin Alphabet No. 1
US-ASCII ASCIIAmerican Standard Code for Information Interchange
UTF-8 UTF8Eight-bit UCS Transformation Format
UTF-16 UTF-16Sixteen-bit UCS Transformation Format, byte order identified by an optional byte-order mark
EUC-JP EUC_JPJISX 0201, 0208 and 0212, EUC encoding Japanese
ISO-2022-JP ISO2022JPJIS X 0201, 0208, in ISO 2022 form, Japanese
Shift_JIS SJISShift-JIS, Japanese
windows-31j MS932Windows Japanese

課題

1.

上記の Xcode.java をつくり実行してみなさい

ファイル名 Xcode.java

適当なテキストファイル xcode00.txt を作って、実行し、xcode01.txt ができていることを確認しなさい。

xcode01.txtをエディタで開いて内容を確認しなさい。

次の二つを実行してファイルの内容を比較しなさい。

java Dump xcode00.txt
java Dump xcode01.txt
$ javac Xcode.java 
$ java Xcode
以上8文字
$ java Dump xcode00.txt 
 41 42 43 e3 80 82 e3 81 82 e3 81 84 e3 81 86  a

以上16バイト
$ java Dump xcode01.txt 
 41 42 43 a1 a3 a4 a2 a4 a4 a4 a6  a
以上12バイト
$

まず、xcode00.txt に xcode.txt とおなじ、「ABC。あいう」と入れ、出力する文字コードを替えて、Dumpし、下の空欄をうめなさい。ISO-2022-JPは素直にいかないかも知れません。

A B C LF
UTF-8 41 42 43 e3 80 82 e3 81 82 e3 81 84 e3 81 86 a
EUC-JP
UTF-16
ISO-2022-JP
ABC。あいう
亜唖娃阿123
dEはひxY
もくじ

Javaプログラミング
聖愛中学高等学校
http://www.seiai.ed.jp/
Aug. 2009 改編