memorandums

日々の生活で問題解決したこと、知ってよかったことなどを自分が思い出すために記録しています。

LoadStrings.java(その後)

昨日のエントリーにコメントをいただき、確かめるために少し調査と実験をしてみました。

まず、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]);
  }
}