Java无法在文件名中打开具有代理Unicode值的文件?

我正在处理使用文件执行各种IO操作的代码,我想让它能够处理国际文件名。 我正在使用Java 1.5处理Mac,如果文件名包含需要代理的Unicode字符,则JVM似乎无法找到该文件。 例如,我的测试文件是:

"草鷗外.gif"被破解成Java字符\u8349\uD85B\uDFF6\u9DD7\u5916.gif

如果我从这个文件名创建一个文件,我无法打开它,因为我得到一个FileNotFoundexception。 即使在包含该文件的文件夹上使用它也会失败:

 File[] files = folder.listFiles(); for (File file : files) { if (!file.exists()) { System.out.println("Failed to find File"); //Fails on the surrogate filename } } 

我实际处理的大部分代码都是以下forms:

 FileInputStream instream = new FileInputStream(new File("草鷗外.gif")); // operations follow 

有没有办法解决这个问题,要么转义文件名,要么以不同的方式打开文件?

我怀疑Java或Mac之一正在使用CESU-8而不是正确的UTF-8。 Java使用“修改过的UTF-8”(这是CESU-8的一个细微变化)用于各种内部目的,但我不知道它可以将它用作文件系统/ defaultCharset。 不幸的是,我这里既没有Mac也没有Java来测试。

“修改”是一种改进的说法“严重错误”。 而不是像𦿶那样输出补充(非BMP)字符的四字节UTF-8序列:

 \xF0\xA6\xBF\xB6 

它为每个代理输出一个UTF-8编码的序列:

 \xED\xA1\x9B\xED\xBF\xB6 

这不是一个有效的UTF-8序列,但无论如何许多解码器都会允许它。 问题是如果你通过一个真正的UTF-8编码器往返,你有一个不同的字符串,上面的四字节字符串。 尝试使用该名称和繁荣访问该文件! 失败。

因此,首先让我们检查文件名实际存储在当前文件系统下的方式,使用一个平台,使用文件名(如Python 2.x)的字节:

 $ python Python 2.x.something (blah blah) Type "help", "copyright", "credits" or "license" for more information. >>> import os >>> os.listdir('.') 

在我的文件系统(Linux,ext4,UTF-8)上,文件名“草𦿶鸥外.gif”出现如下:

 ['\xe8\x8d\x89\xf0\xa6\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif'] 

这就是你想要的。 如果这就是你得到的,那可能是Java做错了。 如果你得到更长的六字节字符版本:

 ['\xe8\x8d\x89\xed\xa1\x9b\xed\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif'] 

它可能是OS X做错了…它总是存储这样的文件名吗? (或者这些文件最初来自其他地方?)如果将文件重命名为“正确”版本怎么办?:

 os.rename('\xe8\x8d\x89\xed\xa1\x9b\xed\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif', '\xe8\x8d\x89\xf0\xa6\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif') 

如果您的环境的默认语言环境不包含这些字符,则无法打开该文件。

请参阅: File.exists()失败,名称中包含unicode字符

编辑:好吧..您需要的是更改系统区域设置。 无论你使用什么操作系统。

编辑

请参阅: 如何在Java中打开包含重音符号的文件?

请参阅: Mac上的JFileChooser无法查看中文字符命名的文件?

这certificate是Mac JVM的问题(在1.5和1.6上测试)。 使用Java File类无法访问包含增补字符/代理项对的文件名。 我最后编写了一个带有Carbon调用的JNI库,用于项目的Mac版本(ick)。 我怀疑CESU-8问题bobince提到,因为JNI调用获取UTF-8字符返回了一个CESU-8字符串。 看起来不像是你可以真正解决的问题。

这是旧的skool java File api中的一个错误,也许只是在Mac上? 无论如何,新的java.nio api工作得更好。 我有几个文件包含无法使用java.io.File和相关类加载的unicode字符和内容。 转换我的所有代码后使用java.nio.Path EVERYTHING开始工作。 我用java.nio.Files替换了org.apache.commons.io.FileUtils(它有同样的问题)…

…并确保使用适当的字符集读取和写入文件内容,例如:Files.readAllLines(myPath,StandardCharsets.UTF_8)