使用jnlp / webstart在OSX上使用Java 7对文件名进行编码问题

时间:2012-11-22 13:22:42

标签: java macos character-encoding java-7 jnlp

我遇到了这个问题,并且已经进行了几天不成功的搜索和解决方法尝试。

我现在有一个内部java swing程序,由jnlp / webstart在osx和windows计算机上发布,除其他外,还从WebDav下载一些文件。

最近,在使用OSX 10.8和Java 7的测试计算机上,带有重音字符的文件名和目录名开始被问号替换。

在7之前的Java版本的OSX上没问题。

示例:

XXXYYY_è_ABCD/

变为

XXXYYY _?_ ABCD /

在原始字符串上使用 java.text.Normalizer (NFD,NFC,NFKD,NFKC),结果不同但仍然错误:

XXXYYY_e?_ABCD /

XXXYYY_e_ABCD /

我知道,来自oracle.com的[andrew.brygin]和[mik3hall at gmail.com]之间的通信

  

是的,file.encoding是根据jvm正在运行的语言环境设置的   on,如果你在xxxx.UTF-8语言环境中运行java vm,那么   file.encoding应该是UTF-8,设置为MacRoman会有问题。   所以我相信Oracle / OpenJDK7的行为正确。那说,安德鲁   Thompson指出,如果所有以前的Apple JDK版本都使用MacRoman   作为英文/ UTF-8语言环境的file.encoding,有一个   这里的“兼容性”问题,可能值得一提   发布说明,为Oracle / OpenJDK MacOS用户提供了一个支持。

original mail

来自 Joni Salonen 博客(java-and-file-names-with-invalid-characters)我知道:

  

您可能知道Java使用“默认字符编码”   将二进制数据转换为字符串。使用他人阅读或书写文字   编码可以使用InputStreamReader或OutputStreamWriter。但   对于API深处的数据到文本转换,您别无选择   更改默认编码。

  

file.encoding怎么样?

     

file.encoding系统属性也可用于设置默认值   Java用于I / O的字符编码。不幸的是,似乎   对文件名如何解码为字符串没有影响。

从jnlp内部执行locale invariabily print

LANG=
LC_COLLATE="C"
LC_CTYPE="C"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL=
使用解决方案的stackoverflow上最类似的问题是: encoding-issues-on-java-7-file-names-in-os-x

但是解决方案是用脚本

包装java程序的执行
#!/bin/bash
export LC_CTYPE="UTF-8" # Try other options if this doesn't work
exec java your.program.Here

但由于webstart,我不认为我可以使用此选项,而且我没有找到任何方法在程序中设置LC_CTYPE环境变量。

任何解决方案或解决方法?

P.S。 :

如果我们直接从shell运行程序,它甚至可以在OSX 10 + Java 7上正确写入文件/目录。 只有JNLP + OSX + Java7

的组合才会出现问题

5 个答案:

答案 0 :(得分:5)

我认为文件名的最大ASCII表示是可以接受的,几乎可以在任何编码中使用。

首先,您要特别使用NFKD,以便以ASCII格式保留最大信息。例如,"2⁵"变为"25"而不仅仅是"2" 一旦非ascii和非控制字符被过滤掉,"fi""fi"变为""而不是String str = "XXXYYY_è_ABCD/"; str = Normalizer.normalize(str, Normalizer.Form.NFKD); str = str.replaceAll( "[^\\x20-\\x7E]", ""); //The file name will be XXXYYY_e_ABCD no matter what system encoding 等。

asdé.txt

然后,您将始终通过此过滤器传递文件名以获取其文件系统名称。你只丢失了一些唯一性,I.E文件asde.txt是一样的 如{{1}},在这个系统中,它们无法区分。

答案 1 :(得分:1)

编辑:在尝试使用OS X后,我意识到我的答案完全错了,所以我正在重做它。

如果您的JVM在JVM命令行上支持-Dfile.encoding=UTF-8,则可能会解决此问题。我相信这是一个标准的财产,但我不确定。

HFS Plus与其他符合POSIX标准的文件系统一样,将文件名存储为字节。但与Linux的ext3文件系统不同,它强制文件名是有效的分解UTF-8。这可以在我的OS X系统上使用Python解释器看到,从空目录开始。

$ python
Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53) 
>>> import os
>>> os.mkdir('\xc3\xa8')
>>> os.mkdir('e\xcc\x80')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 17] File exists: 'e\xcc\x80'
>>> os.mkdir('\x8f')
>>> os.listdir('.')
['%8F', 'e\xcc\x80']
>>> ^D
$ ls
%8F è

这证明文件系统上的目录名称不能进行Mac-Roman编码(即字节值为8F,只要它是è),只要它是HFS Plus文件系统即可。但是,当然,JVM不能确保HFS Plus文件系统,并且SMB和NFS没有相同的编码保证,因此JVM不应该采用这种方案。

因此,您必须说服JVM使用UTF-8编码来解释文件和目录名称,以便正确地将名称读作java.lang.String个对象。

答案 2 :(得分:1)

在黑暗中拍摄:文件编码不会影响文件名的创建方式,只会影响内容如何写入文件 - 请在此处查看此人:http://jonisalonen.com/2012/java-and-file-names-with-invalid-characters/

以下是Apple的简短条目:http://developer.apple.com/library/mac/#qa/qa1173/_index.html

将此与http://docs.oracle.com/javase/tutorial/i18n/text/normalizerapi.html相比较,我认为您要使用

normalized_string = Normalizer.normalize(target_chars, Normalizer.Form.NFD);

在将文件名传递给File构造函数之前规范化文件名。这有帮助吗?

答案 3 :(得分:0)

我认为现在没有真正解决这个问题的方法。

与此同时,我得出结论,从程序内部打印的“C”环境变量来自Java Web Start沙箱,并且(显然,设计上)你不能影响使用jnlp的那些。

接受(由公司接受)解决方法/妥协是使用来自bash脚本的javaws启动jnlp。

显然,从浏览器或finder启动jnlp会创建一个未设置LANG的新沙箱环境(因此设置为等于ASCII的“C”)。 从命令行启动jnlp会从系统默认值中打印出正确的LANG,并从shell继承它。

这允许至少保留jnlp和依赖项的自动更新功能。

无论如何,我们向甲骨文发送了一个错误报告,但我个人并不希望它能在短期内得到解决,如果有的话。

答案 4 :(得分:0)

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

...并确保使用适当的字符集读取和写入文件内容,例如:

Files.readAllLines(myPath, StandardCharsets.UTF_8)