在以下使用 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 并从命令行以 UTF-8 格式提供 file.encoding 和 sun.jnu.encoding 属性,我会得到垃圾输出并且 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 解释文件名的方式。
更新 3现在看起来问题是 Java 如何解释文件名。无论文件编码和 LC_ALL 环境变量的值如何,以下简单的 C 代码都可以在 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');
}
}