【发布时间】:2011-04-06 07:37:54
【问题描述】:
在 OS X 和 Linux 上的 Java 6 中列出目录内容时,我遇到了一个奇怪的文件名编码问题:File.listFiles() 和相关方法似乎返回的文件名与系统其他部分的编码不同.
请注意,导致我出现问题的不仅仅是这些文件名的显示。我主要对文件名与远程文件存储系统的比较感兴趣,所以我更关心名称字符串的内容而不是用于打印输出的字符编码。
这是一个演示程序。它创建一个具有 Unicode 名称的文件,然后打印出从直接创建的文件中获得的文件名的 URL 编码 版本,以及列在父目录下的相同文件(您应该运行此代码在一个空目录中)。结果显示File.listFiles()方法返回的不同编码。
String fileName = "Trîcky Nåme";
File file = new File(fileName);
file.createNewFile();
System.out.println("File name: " + URLEncoder.encode(file.getName(), "UTF-8"));
// Get parent (current) dir and list file contents
File parentDir = file.getAbsoluteFile().getParentFile();
File[] children = parentDir.listFiles();
for (File child: children) {
System.out.println("Listed name: " + URLEncoder.encode(child.getName(), "UTF-8"));
}
这是我在系统上运行此测试代码时得到的结果。请注意 %CC 与 %C3 字符表示。
OS X 雪豹:
File name: Tri%CC%82cky+Na%CC%8Ame
Listed name: Tr%C3%AEcky+N%C3%A5me
$ java -version
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02-279-10M3065)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01-279, mixed mode)
KUbuntu Linux(在同一 OS X 系统上的 VM 中运行):
File name: Tri%CC%82cky+Na%CC%8Ame
Listed name: Tr%C3%AEcky+N%C3%A5me
$ java -version
java version "1.6.0_18"
OpenJDK Runtime Environment (IcedTea6 1.8.1) (6b18-1.8.1-0ubuntu1)
OpenJDK Client VM (build 16.0-b13, mixed mode, sharing)
我尝试了各种技巧来使字符串一致,包括设置file.encoding 系统属性和各种LC_CTYPE 和LANG 环境变量。没有任何帮助,我也不想诉诸此类黑客。
与this (somewhat related?) question 不同,尽管名称很奇怪,我仍可以从列出的文件中读取数据
【问题讨论】:
-
.java文件的编码是什么?我认为您可以使用file命令来确定。 -
超级优秀的解决方案总结!如果更多人这样做,SO 将是一个更好的目的地。
-
优秀的帖子!关于 HSF+ 的最后一句话非常好。 Apple 键盘快捷键生成 NFC,但文件系统标准化为 NFD。当您有一个名为
"AB"(拉丁文脚本)的文件、另一个名为"ΑΒ"(希腊文脚本)和第三个名为"АВ"(西里尔文脚本)的文件时,它仍然没有帮助。通过 gosh-that's-hard-to-type-ness 谈论安全性。 :) 我曾经有一台机器名为 wraeththu,没有人可以输入登录权限的名称。可能更糟:本可以像原来的那样拼写,在古英语中是 wrǽþþu。 :) -
@StephenP 那么你能解释一下为什么 listFiles() 将字符串作为 NFC 返回吗?我很清楚HFS+将它们存储为NFD,那为什么它们不作为NFD返回呢?
-
我在安装的(远程)NFS 卷上的 Mac OS X(确切地说是 10.9.5)上遇到了同样的问题。我想编写一个实用程序,将 NFD 文件名重命名为 NFC 文件名,并在 NFC 和 NFD 文件名都存在时检测名称冲突(我试图创建这两个文件,在我的系统上是允许的)。但是,Java 总是将 NFC 返还给我。实际上,我必须使用
java.nio.file.Paths.get(...)来返回有效路径,在从java.io.File.listFiles()返回的元素上调用exists()可能会返回false!有什么想法吗?
标签: java unicode normalization unicode-normalization file-encodings