gpt4 book ai didi

java - 当使用来自 Oracle 的 Java 7 时,File.list() 在 Mac OS X 上错误地检索具有非 ASCII 字符的文件名

转载 作者:太空狗 更新时间:2023-10-29 22:41:28 25 4
gpt4 key购买 nike

当使用来自 Oracle 的 Java 7 时,我在 Mac OS X 上使用 File.list() 时遇到错误检索到非 ASCII 字 rune 件名的问题。

我正在使用以下示例:

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();
}
}

}

使用 Apple 的 Java 6 运行此示例,一切正常:

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

使用 Oracle 的 Java 7 运行此示例,结果如下:

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

但是,如果我设置环境如下(上面两种情况都没有设置):

LANG=en_US.UTF-8

Oracle 的 Java 7 的结果符合预期:

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

我的问题是我不想设置 LANG 环境变量。这是一个 GUI 应用程序,我想将其部署为 Mac OS X 应用程序,这样做,LSEnvironment 设置

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

在 Info.plist 中无效(另见 here)

如何在 Mac OS X 上从 Oracle 正确检索 Java 7 中的文件名而无需设置 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

因此,如果未设置 LANG(仅来自 Oracle 的 Java 7),那么可以看到 Files.list() 将一些字节替换为 UTF-8 "EF BF BD"= Unicode U+FFFD = 替换字符。

最佳答案

如果其他一切都失败了,请为设置 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(Apple 或 Oracle 的任何版本的 Java)从文件系统读取文件名的方式。文件系统上的文件名本质上是二进制数据,必须对其进行解码才能在 Java 中将其用作 String。 (你可以在我的博客中read more about this issue。)

编码的检测因平台和版本而异,所以这一定是 Apple Java 6 和 Oracle Java 7 不同的地方:Java 6 正确检测系统设置为 UTF-8,而 Java 7 获取错了。

但奇怪的是,当我尝试使用以下程序重现该问题时,我发现 Java 6 和 Java 7 正确使用 UTF-8 解码文件名(它们被正确打印到终端).对于其他 I/O,Java 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());
}
}
}

当我在 OS 10.7 上运行 locale 时,我得到了这个输出。在我的系统上,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=

关于java - 当使用来自 Oracle 的 Java 7 时,File.list() 在 Mac OS X 上错误地检索具有非 ASCII 字符的文件名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12987252/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com