MacのJavaでファイル名を扱う際には気を付けた方が良い、らしい
QTJのエントリでAppleのJavaを思い出したついでに。
年末、合成文字の件でUTF-8に興味を持ったので、少し調査を行った。当時は、UnicodeとUTF-8がどういう関係[1]にあるのかもよく知らず、とりあえずユニバーサルに、何も気にしなくても使用できる便利なもの、という程度の認識だった。
私自身はMacを所有しておらず、確認する術がなかった。そこで、不明な点についてはにちゃんねるのスレッド[2]で質問させていただいた。本エントリを読むよりこちらのスレッドを見た方がわかりやすいかもしれない。
1点目。ファイル名の文字コードについて、Windows(NTFS)ではUnicodeで管理される[3]。ここでUnicodeという言い方はおそらく正しくなく、本来はUTF-8というべきなのだと思う。
[追記: UTF-16だそうだ…というより、ファイルシステム上は文字列というより単なるバイナリ列として扱われている、というほうが正しいのだろうか。
NTFS allows any sequence of 16-bit values for name encoding (file names, stream names, index names, etc.). This means UTF-16 codepoints are supported, but the file system does not check whether a sequence is valid UTF-16 (it allows any sequence of short values, not restricted to those in the Unicode standard).
]
Windowsのファイル名としては、合成文字について、NFD正規化された状態であろうがNFC正規化された状態であろうが、そのまま保存される。したがって、同じ名前の(ようにみえる)ファイルが同一ディレクトリ下に存在する可能性がある。Windowsが同一名であると認識できるのは、文字列が同一バイト列から成る場合だけである。これは、Linuxでも同様のようだ。なお、濁音をNFD正規化した場合、以前のエントリの通り、Windows Vistaより前のバージョン(Windows XPなど)では文字化けする。
2点目。Mac OS(HFS+)でもUTF-8だが、NFD正規化されたコードが用いられる。ただしAppleが独自に変形したNFD正規化であり、正確には正規化とは呼べない[4]。このコード体系は、UTF8-MACと俗称されている。
1点目と2点目より。Windows(やLinux)で日本語をIMEで濁音を入力した場合、変換される文字はNFC正規化されたものであるため、ファイル名の濁音は、一般的にはNFC正規化された文字が使用される。一方でMacではIMEがどう変換しようと濁音はNFD正規化された状態で保存される。この差異が原因で、FTPやWebDAVといったファイル転送を伴なうプロトコル/サービスでしばしば問題が発生する。
3点目。MacのJavaでjava.io.Fileのコンストラクタ引数にファイル名を与える際には、UTF8-MAC文字列である必要はない。NFC正規化文字列を与えてもシステムコールやファイルシステムでUTF8-MACに変換される。一方で、WindowsのSun JDKでは、引数に与えた文字列がそのままファイル名に用いられる。つまり、NFC正規化文字列を与えた場合とNFDの場合では異なるファイルが作られる。
4点目。Apple実装のMac Javaでは、Fileの各種メソッドから得られるString型のファイル名は、NFC正規化されたものである(UTF8-MAC符号化されたものではない)。
2点目と4点目より。Macの実際のファイル名はNFD正規化(に似たUTF8-MAC符号化)された文字列であるのに対し、Java上ではNFC正規化された文字列で扱われることになる。Javaだけで完結するシステムであれば問題ないかもしれないが、他の言語のプログラムと連携するような場合には問題が起こりそうな気がする。
再度2点目と4点目より。前述した通り、UTF8-MACは正規化されていない文字がある。しかしFileのメソッドで取得した文字列はNFC正規化される。したがって、異なる2つのファイル名を取得しようとした場合でも、区別の付かない同一文字列が返ってくる場合がある。具体的には”雪羽”と”雪羽”はUTF8-MACにおいては区別される([4]より。”羽”はU+7FBD、”羽”はU+FA1E)が、NFC正規化するとどちらも同一の文字列”雪羽”になる(NFD正規化も同様)。つまり、ファイルシステム上は別個のものとして扱われるがJava上では同一とみなされてしまう。
5点目。NFC正規化やNFD正規化を行う際、Javaではjava.text.Normalizerクラスのメソッドを使用すればよいのだが、導入されたのがJava6である。MacでJava6以降を動作条件にしても良いのか分からない。
参考:
- [1]UnicodeとUTF-8の違いは? – おつあり
- [2]MacでJava その4 172-187 – 2ch.net
- [3]Windows のファイル名の文字コードについて – IBM Linux at IBM
- [4]Text Encodings in VFS – Apple Developer Connection
- JIS X 0213の改正は、文字コードにどんな未来をもたらすか(7) 番外編:改正JIS X 0213とUnicodeの等価属性/正規化について(上) 及び (下) – INTERNET Watch
« [読書]QuickTime for Java – A Developer’s Notebook | トップページ | ネットワークスペシャリスト試験に合格した »
この記事へのコメントは終了しました。
トラックバック
この記事へのトラックバック一覧です: MacのJavaでファイル名を扱う際には気を付けた方が良い、らしい:
» 朝のささやかなぜいたく [愛と苦悩の日記]
■朝のささやかなぜいたくに、レギュラーコーヒーを飲んでいるのだが、フィルターペーパーがなくなったので会社帰りコンビニに寄った。当然1人用フィルターを使っているのでペーパーも1人用をさがしたが、2人用しかない。コンビニに1人用を置いていないのはおかしい。単身者差別? ■会社の時間は僕個人の時間の3倍くらいゆっくり流れる。 ■今日はJAVAのswingでRMIアプリのGUIを作っていた。GridBag...... [続きを読む]
« [読書]QuickTime for Java – A Developer’s Notebook | トップページ | ネットワークスペシャリスト試験に合格した »
コメント