iSeries Java でのテキストファイル作成時の問題

Java からの IFS ファイルの作成

OS/400 上の IFS に Java からテキストファイルを作成することができます。

たとえば、添付文書の保存の時に使った

PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(filename)));

や、CSV ファイルへの読み書き時の注意の時の

OutputStreamWriter fwtemp = new OutputStreamWriter(new FileOutputStream(file), "Cp943c");
fwtemp.write("Create New File with CCSID 943");
PrintWriter pwtemp = new PrintWriter(fwtemp);
fwtemp.close();
pwtemp.close();

などのやり方でテキストファイルが作成されます。

ファイルの CCSID の決定

ファイルが作成される時にはそのファイルを作成するプログラムの実行環境である JVM が持っている Java のシステム・プロパティの中に file.encoding というプロパティがあり、この値をみてファイル自体の CCSID が決定されます。

現在 V5R1 での file.encoding のデフォルトは Cp943c になっています。

以下の例のように OutputStreamWriter で変換先を指定できますが、この場合はそのエンコーディングの値にあわせて作成されるのが確認できました。

OutputStreamWriter fwtemp = new OutputStreamWriter(new FileOutputStream(file), "Cp943c");
fwtemp.write("Create New File with CCSID 943");
PrintWriter pwtemp = new PrintWriter(fwtemp);
fwtemp.close();
pwtemp.close();

ただし、"MS932" などを指定すると Java を稼動させているジョブの CCSID をそのまま使った IFS ファイルが作成されてしまいます。
たとえば、以下のコードの場合、CCSID 5035 の属性がついた、内容が MS932 で書き込まれたファイルが作成されます。
(最初に書いた後の追記: もう一度確認のためにテストし直してみたところ、ちゃんと 943 で作成されてしまいました。??? いったいどういうことなのか ...その後は何回やってみても MS932 の指定では CCSID 943 でファイルが作成されますので、上で言ったことは気にしなくていいかもしれません)

OutputStreamWriter fwtemp = new OutputStreamWriter(new FileOutputStream(file), "MS932");

ちなみに、この OutputStreamWriter は Stream を Writer に変換するためにも便利なクラスです。
たとえば

OutputStreamWriter fwtemp = new OutputStreamWriter(new FileOutputStream(file));

FileWriter fwtemp = new FileWriter(file);

と同等です。
Stream を入力にして Writer に書き出したい、といった時にはこの書き換えが有効です。

Java のエンコーディングの非互換性

また、デフォルトのエンコーディングである Cp943c のままでは、以下の 5文字が MS932 と Cp943c で変換先のコードポイントが異なるために変換されないことがあります。

−〜‖―U

CSV ファイルへの読み書き時の注意の時に、わざわざ以下のように Cp943c のファイルを作成してから MS932 でデータを変換しているのは以上の 2つの理由 (変換には MS 932 を使用したいがファイルの属性には CCSID 943 を使用したい) によるものです。
そういう意味では以下のコードは iSeries で特有のコードになってしまっている、とは言えるでしょう。
(最初に書いた後追記: これも上でふれたように再テストの際には問題がなくなってしまったので、この一連のコードは必要ないかもしれません。ま、今のところあっても大勢に影響はないのですが ...)

File file = new File("test001.csv");
if (file.exists())
{ }
else {
OutputStreamWriter fwtemp = new OutputStreamWriter(new FileOutputStream(file), "Cp943c");
fwtemp.write("Create New File with CCSID 943");
PrintWriter pwtemp = new PrintWriter(fwtemp);
fwtemp.close();
pwtemp.close();
}

OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(file), "MS932");
BufferedWriter bw = new BufferedWriter(fw);
PrintWriter pw = new PrintWriter(bw);

ドミノは内部的には LMBCS (Lotus Multi-Byte Character Set) という文字コードを使用しています。
そのため、getItemValueString メソッドなどを使用してドミノのデータを取得する際には、この LMBCS から Java の内部処理コードである Unicode への変換が行なわれていると考えられるのですが、これが MS932 と同じロジックで上に挙げた 5つの非互換文字を変換しているのでしょう。

CCSID というものはファイルの内容を示す単なるラベルであり、ファイルの内容と適合しているかどうかはファイル作成時に正しく設定すべきことです。基本的に自動で OS/400 はこの整合性をとることができるようにファイルを作成してくれるのですが、MS932 のように OS/400 で対応する CCSID がない場合はデフォルトで実行環境の CCSID を使用してファイルを作成します。
そのため、ファイルの CCSID の決定で触れたように、CCSID 5035 でファイルが作成されるが内容はPC コードページ(MS932) である、といったことがおきてしまうケースがあります。
いかにも仕様の谷間に落ちてしまったような状況なのですが、まあしかたのないことでしょう。
そのため、ここで書いたようなコードが必要になってしまっているわけです。
(最初に書いた後追記: さっき書いたようにその必要はないかもしれません ...)

まあ、どのみち文字変換関係は (特に日本語環境では) いつでもいろいろな問題がありますので、若干の苦労はしかたないんでしょうね。
それもこれも日本が IT 関係でリーダーシップを取れてないということを示しているようにも思えます。

[Top Pageに戻る]

Ads by TOK2