Xol*_*lve 6 java linux encoding file internationalization
在使用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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果我将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如何解释文件名.
更新3现在看来问题是Java如何解释文件名.以下简单的C代码适用于Linux,无论文件编码和LC_ALL环境变量的值如何(我很高兴这证明了这里给出的答案: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');
}
}
Run Code Online (Sandbox Code Playgroud)
注意:所以最后我认为我已经把它钉死了.我没有证实这是对的.但是通过一些代码读取和测试,这是我发现的,我没有额外的时间来研究它.如果有人有兴趣,他们可以检查出来,并告诉我这个答案是对还是错 - 我会很高兴:)
我使用的引用来自OpenJDK网站上提供的这个tarball: openjdk-6-src-b25-01_may_2012.tar.gz
Java在本方法中将所有字符串本地转换为平台的本地编码:jdk/src/share/native/common/jni_util.c - JNU_GetStringPlatformChars()
.系统属性sun.jnu.encoding
用于确定平台的编码.
使用libc的方法sun.jnu.encoding
设置值.环境变量用于设置值.使用Java选项在命令提示符处给出的值将被忽略.jdk/src/solaris/native/java/lang/java_props_md.c - GetJavaProperties()
setlocale()
LC_ALL
sun.jnu.encoding
-Dsun.jnu.encoding
调用File.exists()
已在文件中编码,jdk/src/share/classes/java/io/File.java
并返回为
return ((fs.getBooleanAttributes(this) & FileSystem.BA_EXISTS) != 0);
getBooleanAttributes()
天然地编码(和我跳过码步骤,通过多种文件浏览)的jdk/src/share/native/java/io/UnixFileSystem_md.c
函数:
Java_java_io_UnixFileSystem_getBooleanAttributes0()
.这里宏
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path)
将路径字符串转换为平台的编码.
因此,转换为错误的编码实际上会向后续的stat()
方法调用发送错误的C字符串(char数组).它将返回结果无法找到文件.
课程: LC_ALL
非常重要
我不确定你在哪里读到file.encoding
.我没有看到它与其他标准属性System.getProperties
一起提到.但从我的实验来看,似乎这个值会影响文件内容的编码,而不会影响文件名.System.out
特别是如果file.encoding
是,则不会打印非ASCII字符POSIX
.
另一方面,决定哪种编码应用于文件名的Linux方法是LC_CTYPE
当前语言环境设置的方面.我认为Java没有理由覆盖它.由于许多其他平台(特别是Windows)始终将Unicode用于文件名而不是字节,因此将文件系统的字节级详细信息暴露给Java应用程序几乎没有意义.
归档时间: |
|
查看次数: |
7335 次 |
最近记录: |