Java 環境変数 LANG=C だと 日本語ファイル名がうまく扱えない


環境変数 `LANC=C` で 日本語ファイル名を扱いたいと思っています。

# 内容

しかし、以下の様な Java のプログラムで日本語ファイル名を読もうとすると  
`LANG` の設定によってはうまくいきません。

[code]

    import java.io.File;
    class Test {
        static public void main(String args[]){
            File dir = new File("somedir");
            for (String f : dir.list())
                System.out.println(f);
        }
    }
    
[/code]

実行すると、こんな感じになります。

[code]

    % echo $LANG
    ja_JP.UTF-8
    % java Test
    い
    う
    あ
    
    % LANG=C java Test
    ???
    ???
    ???
    
[/code]

## 前提条件

日本語ファイル名のファイルは事前に以下の様に作りました。

[code]

    % mkdir somedir
    % touch somedir/あ
    % touch somedir/い
    % touch somedir/う
    
[/code]

## Javaのプロパティ

関係ありそうだなと思ったので、  
`LANG` が `ja_JP.UTF-8` と `C` の場合の  
`System.getProperties()` の差を調べると  
以下の4点が違う様でした  
\- user.country  
\- user.language  
\- sun.jnu.encoding  
\- file.encoding

以下を `C` と `ja_JP.UTF-8` で実行してみて `diff` で調べました。

[code]

    class Prop {
        static public void main(String args[]){
            java.util.Properties p = System.getProperties();
            for (Object k : p.keySet())
                System.out.println(k + ": " + p.get(k));
        }
    }
    
[/code]

それで以下の様に `LANG=C` にして、  
上の4つを `ja_JP.UTF-8` のときと同じになる様に実行してみましたが  
やはりうまく表示されません。

[code]

    % LANG=C java -Dfile.encoding=UTF-8 \
                  -Dsun.jnu.encoding=UTF-8 \
                  -Duser.country=JP \
                  -Duser.language=ja \
                  Test
    
[/code]

でも、最初に `LANG=C java Test` で実行したときとは  
違う文字が出ている様でした。  
どちらにしろ読めないですが

# 出力まとめ

出力はまとめると以下の様になります

[code]

    # うまく表示される
    % java Test | hexdump -C
    00000000  e3 81 84 0a e3 81 86 0a  e3 81 82 0a              |............|
    0000000c
    
    # うまく表示されない
    % LANG=C java Test | hexdump -C
    00000000  3f 3f 3f 0a 3f 3f 3f 0a  3f 3f 3f 0a              |???.???.???.|
    0000000c
    
    # うまく表示されない    
    % LANG=C java -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Duser.country=JP -Duser.language=ja Test | hexdump -C
    00000000  ef bf bd ef bf bd ef bf  bd 0a ef bf bd ef bf bd  |................|
    00000010  ef bf bd 0a ef bf bd ef  bf bd ef bf bd 0a        |..............|
    0000001e
    
[/code]

# 環境

OS は Ubuntu です

[code]

    % cat /etc/issue
    Ubuntu 14.04.4 LTS \n \l
    % uname -a
    Linux ub 3.13.0-74-generic #118-Ubuntu SMP Thu Dec 17 22:52:10 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
    % java -version
    java version "1.8.0_77"
    Java(TM) SE Runtime Environment (build 1.8.0_77-b03)
    Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode)
    
[/code]

なにかヒントが頂けるとうれしいです。  
また、ここを調べた方がいいというポイントがあれば、教えて下さい。  
よろしくお願いします。




各種プロパティを手動で設定したときに出力される `ef bf bd`
は、Unicodeで表現できない文字を表す[「置換文字」](http://smdn.jp/programming/netfx/tips/encoding_fallback/)のUTF-8表現です。Javaは内部的に文字列をUTF-16で扱っているようなので、
`dir.list()` の時点で前述の置換文字に化けていて、それを `3f` で出すか `ef bf bd`
で出すかが切り替わっているだけなのではないでしょうか。

調べてみると、`java.io.File`
でのファイル名の扱いはロケール設定やOSによって変化するという話がちらほら見つかります。Macでは動いたというのはこのあたりの絡みかもしれません。

  * [java read write unicode / UTF-8 filenames (not contents) - Stack Overflow](https://stackoverflow.com/q/14171565/2818869)
  * [How can I open files containing accents in Java? - Stack Overflow](https://stackoverflow.com/q/3072376/2818869)

どちらの質問にも `java.nio.Files`
で解決したという情報が寄せられているので、ひょっとしたらこれで解決するかもしれません。（標準出力へ書き出す際のエンコーディングは別途考慮が必要だと思いますが）




各種プロパティを手動で設定したときに出力される `ef bf bd`
は、Unicodeで表現できない文字を表す[「置換文字」](http://smdn.jp/programming/netfx/tips/encoding_fallback/)のUTF-8表現です。Javaは内部的に文字列をUTF-16で扱っているようなので、
`dir.list()` の時点で前述の置換文字に化けていて、それを `3f` で出すか `ef bf bd`
で出すかが切り替わっているだけなのではないでしょうか。

調べてみると、`java.io.File`
でのファイル名の扱いはロケール設定やOSによって変化するという話がちらほら見つかります。Macでは動いたというのはこのあたりの絡みかもしれません。

  * [java read write unicode / UTF-8 filenames (not contents) - Stack Overflow](https://stackoverflow.com/q/14171565/2818869)
  * [How can I open files containing accents in Java? - Stack Overflow](https://stackoverflow.com/q/3072376/2818869)

どちらの質問にも `java.nio.Files`
で解決したという情報が寄せられているので、ひょっとしたらこれで解決するかもしれません。（標準出力へ書き出す際のエンコーディングは別途考慮が必要だと思いますが）

