的File.List()从Oracle使用Java 7时,错误地在Mac OS X检索与非ASCII

2019-07-01 11:27发布

我使用的File.List()与从Oracle使用Java 7时,在Mac OS X正确检索非ASCII字符的文件名有问题。

我使用下面的例子:

import java.io.*;
import java.util.*;

public class ListFiles {

  public static void main(String[] args) 
  {
    try { 
      File folder = new File(".");
      String[] listOfFiles = folder.list(); 
      for (int i = 0; i < listOfFiles.length; i++) 
      {
        System.out.println(listOfFiles[i]);
      }
      Map<String, String> env = System.getenv();
      for (String envName : env.keySet()) {
        System.out.format("%s=%s%n",
            envName,
            env.get(envName));
      }
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
  }

}

运行在Java 6苹果这个例子中,一切都很好:

....
Folder-ÄÖÜäöüß
吃饭.txt
....

运行在Java 7甲骨文这个例子中,结果如下:

....
Folder-A��O��U��a��o��u����
������.txt
....

但是,如果我设置环境如下(在上述两种情况下不设置):

LANG=en_US.UTF-8

不出所料与Java 7甲骨文的结果:

....
Folder-ÄÖÜäöüß
吃饭.txt
....

我的问题是,我不希望设置LANG环境变量。 这是我要部署为Mac OS X的应用程序中的GUI应用程序,并且这样做,LSEnvironment设置

<key>LSEnvironment</key>
<dict>
  <key>LANG</key>
  <string>en_US.UTF-8</string>
</dict>

在Info.plist的手段都不起作用时(见这里 )

我能做些什么来获取正确的Java 7中从Oracle在Mac OS X中的文件名,而不必设置LANG环境? 在Windows和Linux,这个问题不存在。

编辑:

如果我打印单个字节有:

byte[] x = listOfFiles[i].getBytes();
for (int j = 0; j < x.length; j++) 
{
    System.out.format("%02X",x[j]);
    System.out.print(" ");
}
System.out.println();

正确的结果是:

Folder-ÄÖÜäöüß
46 6F 6C 64 65 72 2D 41 CC 88 4F CC 88 55 CC 88 61 CC 88 6F CC 
88 75 CC 88 C3 9F 
吃饭.txt
E5 90 83 E9 A5 AD 2E 74 78 74 

而错误的结果是:

Folder-A��O��U��a��o��u����
46 6F 6C 64 65 72 2D 41 EF BF BD EF BF BD 4F EF BF BD EF BF BD 
55 EF BF BD EF BF BD 61 EF BF BD EF BF BD 6F EF BF BD EF BF BD 
75 EF BF BD EF BF BD EF BF BD EF BF BD  
������.txt
EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD 2E 74 78 74 

因此,人们可以看到,Files.list()取代一些字节用UTF-8 “EF BF BD”= Unicode的U + FFFD =替换字符,如果未设置LANG(仅爪哇7从Oracle)。

Answer 1:

如果一切都失败了,请为设置环境变量LC_CTYPE的JVM的包装,然后启动你的应用程序。 OS X不关心哪个程序plist中告诉它运行的不是吗? 这可能是最简单的创建此包装在shell脚本:

#!/bin/bash
export LC_CTYPE="UTF-8" # Try other options if this doesn't work
exec java your.program.Here

问题是与方式的Java - Java的任何版本,无论从苹果公司或Oracle - 从文件中读取系统文件的名称。 在文件系统上的文件的名称基本上是二进制数据,并且必须以使用它们作为字符串在Java中进行解码。 (你可以阅读更多关于这个问题在我的博客。)

编码的检测,从平台到平台和版本的升级而改变,所以这一定是其中苹果的Java 6和Oracle Java 7的不同:Java 6中正确地检测到系统设置为UTF-8,而Java 7得到它错了。

奇怪的是,虽然,当我尝试重现该问题与以下程序我发现,包括Java 6和Java 7 正确使用UTF-8的文件名解码(它们被正确地打印到终端)。 对于其它I / O,爪哇6u35使用的MacRoman作为默认的字符集,而Java 7u7使用UTF-8(由所示file.encoding系统属性)。

import java.io.*;

public class Test {
  public static void main(String[] args) {
    System.setOut(new PrintStream(System.out, true, "UTF-8"));
    System.out.println(System.getProperty("file.encoding"));
    for (File f: new File(".").listFiles) {
      System.out.println(g.getName());
    }
  }
}

当我运行locale在OS 10.7,我得到这个输出。 看来,我的系统上的Java 6不正确解释为LC_CTYPE给定的值。 据我知道系统有没有自定义,一切都设置为英语,所以这应该是默认配置:

LANG=
LC_COLLATE="C"
LC_CTYPE="UTF-8"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL=


Answer 2:

由于从运行的Java6给出正确的结果,将这样的:

System.out.println(new String(listOfFiles[i].getBytes(),"UTF-8"));

解决这个问题?

这表明构造明确地解释该listOfFiles [I]字符串作为UTF-8编码的字符串。

编辑:

因为它是不工作这意味着UTF-8不为OS X的默认编码。 维基百科说的Mac OS罗马是,虽然。 因此,我建议您点尝试:

System.out.println(new String(listOfFiles[i].getBytes(),"MacRoman"));

但应该是相同的

System.out.println(new String(listOfFiles[i].getBytes()));

因此,如果这是不是也工作,导致结论,这可能是一个错误的谭安德在你的问题评论说。



Answer 3:

这是一个在OpenJDK的一个已知的bug。 OS X 10.6和OS X 10.7返回默认语言环境不同的值。 见错误http://java.net/jira/browse/MACOSX_PORT-204和http://java.net/jira/browse/MACOSX_PORT-165 。 如果你有这个问题,投票得到它固定。



Answer 4:

降级的JDK内置的Mac OSX版JDK。 如果你这样做,问题应该消失。

此外,您可能还需要设置你的运行配置在Eclipse为UTF-8上运行。



Answer 5:

这是在旧的Java文件API中的错误(也许只是在Mac)。 无论如何,这一切都固定在新的java.nio。

我有一个包含在失败java.io.File的使用和相关类加载的文件名和内容Unicode字符的几个文件。 将我所有的代码,使用后java.nio.Path一切都开始工作。 而我换成org.apache.commons.io.FileUtils(具有同样的问题)与java.nio.Files ...

...并且一定要阅读和使用适当的字符集写文件的内容,例如:Files.readAllLines(mypath中,StandardCharsets.UTF_8)



文章来源: File.list() retrieves file names with NON-ASCII characters incorrectly on Mac OS X when using Java 7 from Oracle