繁体   English   中英

Java 无法打开文件名中包含代理 Unicode 值的文件?

[英]Java Can't Open a File with Surrogate Unicode Values in the Filename?

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

破解成Java字符\草\?\?\鷗\外.gif "草鷗外.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
    }
}

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

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

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

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

“Modified”是“badly bugged”的一种修改方式。 而不是为像𦿶这样的补充(非 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 看不到以中文字符命名的文件?

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM