昨日のエントリーにコメントをいただき、確かめるために少し調査と実験をしてみました。
まず、Unicode文字についてですが、プログラミング言語Java第3版の9Pに以下のように書かれています。「処理する前」というのがちょっと曖昧ですがVMでclassファイルが実行されるとき、と解釈していいと思います。まだすっきりしませんが、とりあえず後日勉強するとして。。。
ほとんどのコードは、7ビット文字コード標準であるASCIIか、Latin-1として呼ばれている8ビット文字コード標準であるISO Latin-1で書かれています。しかし、これらの文字は、処理する前にUnicodeに変換されますので、文字コードは常にUnicodeです。
で、次はfile.encodingのオプション指定ですが、これはこちらのサイトには「Java実行時のデフォルト文字コード変換を設定します」とあります。javacもjavaプログラムであるため、このオプション指定の影響を受けるようです。実験として.bash_profileにexport _JAVA_OPTIONS="-Dfile.encoding=UTF-8"を指定した上で、ターミナルからjavacを実行すると以下のように表示されます。
javac(エンターキー)
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
この指定を外すとmac(UTF-8)で作成した以下のJavaプログラムはコンパイルエラーになります。
class A { public static void main(String [] args){ System.out.println("たかはし"); } }
■エラー
javac A.java
A.java:4: ?x??:???̕????́A?G???R?[?f?B???O SJIS ?Ƀ}?b?v?ł??܂???B
System.out.println("たかは??);
^
A.java:4: ?????e????????????Ă??܂???B
System.out.println("たかは??);
^
A.java:4: ';' ??????܂???B
System.out.println("たかは??);
^
A.java:6: ?\????͒??Ƀt?@?C???̏I???Ɉڂ?܂???
}
^
?G???[ 3 ??
?x?? 1 ??
つづいてProcessingについて確認します。昨日、掲載したLoadStrings.javaを再掲します。Processingプログラムが採用しているfile.encodingを表示する行を追加しています。
import java.io.*; import java.util.*; class LoadStrings { public static String[] load(String fname) { System.out.println(System.getProperty("file.encoding")); //追加 ArrayList list = new ArrayList(); try { FileReader in = new FileReader(fname); BufferedReader br = new BufferedReader(in); String line; while ((line = br.readLine()) != null) { list.add(line); } br.close(); in.close(); } catch (IOException e) { System.out.println(e); } return (String[])list.toArray(new String[0]); } }
■実験1
.bash_profileにexport _JAVA_OPTIONS="-Dfile.encoding=UTF-8"を指定し、Processing.appを通常起動(ダブルクリックで起動)し上記クラスを含む、あるProcessingプログラムを実行した。
■結果
file.encoding→SJIS
SJISファイルを上記クラスで読み込み画面表示→文字化けなし
■実験2
.bash_profileにexport _JAVA_OPTIONS="-Dfile.encoding=UTF-8"を外し、Processing.appを実行。
■結果
file.encoding→SJIS
SJISファイルを上記クラスで読み込み画面表示→文字化けなし
実験1、2よりProcessing.appでは _JAVA_OPTIONSの指定は影響せずSJISで起動するようです。JDK6のデフォルトがSJISなのでそのまま引き継いでいるようです。ちなみにpdeファイルの文字コードを調べるとUTF-8でした。このあたりはProcessing側のデフォルトがUTF-8のためJDKの文字コード(SJIS)と折り合いをつけているものと思います。
ちなみに、Processing.appを手動で起動(/Applications/Processing.app/Contents/MacOS/JavaApplicationStubをターミナルで直接実行)すると、.bash_profileの指定が影響するようです。つまり、_JAVA_OPTIONS="-Dfile.encoding=UTF-8"を活かすと、file.encoding→UTF-8となり、SJISファイルを上記クラスで読み込み画面表示→文字化け、になります。
で、補足的ですが、file.encodingによって影響を受けるのはプログラムコードの文字コードだけではなく、文字コードを指定するクラスのデフォルトの文字コードも影響を受けます。昨日のLoadStrings.javaではファイルの読み込みにFileReaderを使っていたため文字コードの指定ができませんでした。そのため、(macのJDK6では)デフォルトの文字コードとしてSJISが選択されて、SJISファイルの読み込みに成功したのでした。上記のようにProcessing.appは.bash_profileの指定に影響を受けないため、昨日のエントリーに書いた「わけのわからない」結果になったと思います。
くどくて申し訳ありませんが。。。以下のようにInputStreamReaderを使うと読み込むファイルの文字コードを指定することができます。最初からこう書いておけば何も問題は無かったのですが。。。いろいろとProcessingとJavaの関係が少しわかったような気がしました。
import java.io.*; import java.util.*; class LoadStrings { public static String[] load(String fname, String encoding) { ArrayList list = new ArrayList(); try { FileInputStream is = new FileInputStream(fname); InputStreamReader in = new InputStreamReader(is, encoding); BufferedReader br = new BufferedReader(in); String line; while ((line = br.readLine()) != null) { list.add(line); } br.close(); in.close(); } catch (IOException e) { System.out.println(e); } return (String[])list.toArray(new String[0]); } }