OpenJDK 1.6.0_22 を使用して Linux で実行されている次の Java プログラムでは、コマンド ラインでパラメーターとして取り込まれたディレクトリの内容を単にリストしています。このディレクトリには、ファイル名が UTF-8 (ヒンディー語、マンダリン、ドイツ語など) のファイルが含まれています。
import java.io.*;
class ListDir {
public static void main(String[] args) throws Exception {
//System.setProperty("file.encoding", "en_US.UTF-8");
System.out.println(System.getProperty("file.encoding"));
File f = new File(args[0]);
for(String c : f.list()) {
String absPath = args[0] + "" + c;
File cf = new File(args[0] + "/" + c);
System.out.println(cf.getAbsolutePath() + " --> " + cf.exists());
}
}
}
LC_ALL 変数を en_US.UTF-8 に設定すると、結果は正常に出力されます。しかし、LC_ALL 変数を POSIX に設定し、file.encoding および sun.jnu.encoding プロパティをコマンド ラインから UTF-8 として指定すると、ガベージ出力が得られ、cf.exists() は false を返します。
この振る舞いを説明してください。私が非常に多くのウェブサイトで読んだように、 file.encoding はファイル名を読み取って操作に使用するのに十分であると言われています。ここでは、そのプロパティはまったく効果がないように見えます。
更新 1: file.encoding を GBK (中国語) などに設定し、LC_ALL 変数を en_US.UTF-8 に設定すると、cf.exists() は true を返します。のみ '?' ファイル名の代わりに表示されます。驚きo_O。
更新 2:さらに調査すると、Java の問題ではないようです。Linux の libc はロケール設定を使用してファイル名のエンコーディングを変換しているように見えますが、これらの設定により、ファイルが見つからないというエラー/例外が発生します。「file.encoding」は、Java がファイル名を解釈する方法です。
Update 3 Java がファイル名を解釈する方法に問題があるようです。次の単純な C コードは、ファイル エンコーディングと LC_ALL 環境変数の値に関係なく、Linux で動作します (これがここで与えられた答えを証明することを嬉しく思います: https://unix.stackexchange.com/questions/39175/understanding-unix-file-名前エンコード)。しかし、Java が LC_ALL 変数をどのように解釈するかはまだはっきりしていません。そのためのOpenJDKコードを調べています。
サンプル C コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
char *argdir = argv[1];
DIR *dp = opendir(argdir);
struct dirent *de;
while(de = readdir(dp)) {
char *abspath = (char *) malloc(strlen(argdir) + 1 + strlen(de->d_name) + 1);
strcpy(abspath, argdir);
abspath[strlen(argdir)] = '/';
strcpy(abspath + strlen(argdir) + 1, de->d_name);
printf("%d %s ", de->d_type, abspath);
FILE *fp = fopen(abspath, "r");
if (fp) {
printf("Success");
}
fclose(fp);
putchar('\n');
}
}