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)