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

Bea*_*ear 12 java unicode filenames file surrogate-pairs

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

"???.gif" 它被分解为Java字符 \u8349\uD85B\uDFF6\u9DD7\u5916.gif

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

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

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

FileInputStream instream = new FileInputStream(new File("???.gif"));
// operations follow
Run Code Online (Sandbox Code Playgroud)

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

bob*_*nce 7

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

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

\xF0\xA6\xBF\xB6
Run Code Online (Sandbox Code Playgroud)

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

\xED\xA1\x9B\xED\xBF\xB6
Run Code Online (Sandbox Code Playgroud)

这不是有效的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('.')
Run Code Online (Sandbox Code Playgroud)

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

['\xe8\x8d\x89\xf0\xa6\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif']
Run Code Online (Sandbox Code Playgroud)

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

['\xe8\x8d\x89\xed\xa1\x9b\xed\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif']
Run Code Online (Sandbox Code Playgroud)

它可能是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')
Run Code Online (Sandbox Code Playgroud)

  • 这不是一个错误,因为它是规范的一部分(即使它经常令人困惑.) (2认同)

JCa*_*sso 5

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

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

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

编辑

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

请参阅:Mac 上的 JFileChooser 看不到以中文字符命名的文件?