【问题标题】:File name charset problem in javajava中的文件名字符集问题
【发布时间】:2012-04-13 21:01:38
【问题描述】:

当文件名有重音符号时,由于字符集不匹配,尝试打开一个文件时它指出找不到该文件。 我在 linux 系统上使用 UTF-8(/etc/locales 也设置了 UTF-8)。使用 -Dfile.encoding=UTF-8 和环境变量 JBOSS_ENCODING="UTF-8" 运行 jboss

通过 JSP,我得到了文件名:

String fileName = element.getChildText("FileName");
out.println("File to be opened : " + filename);

显示:

要打开的文件:aaaaa.txt

但是,新的 File(fileName) 不起作用。只是 file.exists() 是假的。

尝试:

File[] files = dir.listFiles();
for (int i=0; i<files.length; i++){
      out.println(fileName);

我明白了:aaaaà .txt

为什么它会读取并尝试打开将 HDD 中的文件获取为 ISO-8859-1 的文件? 它是 JBoss 配置吗?一个java配置?如何强制 java.io.File 使用 UTF-8 作为文件名字符集读取文件?

我用过其他工具,名字总是读得很好,使用 UTF-8。

(注意我总是在谈论文件名,而不是内容,它可能是一个空文件)

【问题讨论】:

  • -Dfile.encoding=UTF-8 是特定于 Sun/Oracle JVM 的。你用的是什么JVM?即便如此,你毕竟根本不应该使用这个论点。
  • @BalusC:我不确定你的意思。至少 IBM JVM 也支持“-Dfile.encoding”标签(我不确定今天有多少其他 JVM 正在认真使用)。
  • JVM 是Java Hotspot,反正符合评论
  • 我在 Linux 上尝试过同样的方法,但也失败了。尽管我尝试了LANGLC_ALLfile.encodingsun.jnu.encoding 的所有组合,但Java 无法正确获取文件名,但均未成功。还有什么想法吗?
  • 没有更多的想法。似乎方法是轮询字符集并尝试每个人。

标签: java encoding jboss


【解决方案1】:

我正在尝试找出问题所在。这是我已经拥有的:

Exists.java

import java.io.*;

public class Exists {
  public static void main(String[] args) {
    new File("aaa").exists();
    new File("aaa\u00E4").exists();
    new File("aaa\u00C3\u00A4").exists();
  }
}

还有java -version:

java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01, mixed mode)

现在进入有趣的部分:

$ strace -f -o strace.out java Exists && grep 'stat("aaa' strace.out
31942 stat("aaa", 0x41464950)           = -1 ENOENT (No such file or directory)
31942 stat("aaa\303\244", 0x41464950)   = -1 ENOENT (No such file or directory)
31942 stat("aaa\303\203\302\244", 0x41464950) = -1 ENOENT (No such file or directory)

好消息是 strace 在字节级别上工作,而不是像 Java 那样在字符级别上工作。所以在这种情况下一切都很好。我将环境变量LANG 设置为en_US.UTF-8,所有LC_* 变量都未设置。

现在将问题追踪到一个最小的工作示例:

$ strace -f -o strace.out env - LC_ALL=en_US.UTF-8 /home/roland/bin/java Exists && grep 'stat("aaa' strace.out
31968 stat("aaa", 0x41a75950)           = -1 ENOENT (No such file or directory)
31968 stat("aaa\303\244", 0x41a75950)   = -1 ENOENT (No such file or directory)
31968 stat("aaa\303\203\302\244", 0x41a75950) = -1 ENOENT (No such file or directory)

这仍然有效。所以让我们尝试另一种编码:

$ strace -f -o strace.out env - LANG=en_US.ISO-8859-1 /home/roland/bin/java Exists && grep 'stat("aaa' strace.out
32070 stat("aaa", 0x407a3950)           = -1 ENOENT (No such file or directory)
32070 stat("aaa?", 0x407a3950)          = -1 ENOENT (No such file or directory)
32070 stat("aaa??", 0x407a3950)         = -1 ENOENT (No such file or directory)

所以这行不通。一个可能的原因可能是我选择的语言环境不在locale -a 打印的列表中。但这不应该是 Java 将字母转换为问号的原因。

只要 LANG 指向一个不存在的语言环境,sun.jnu.encoding 属性的设置就不再有任何效果。所以我现在没有主意了。

【讨论】:

  • 在尝试使用 UTF-8 编码 ISO 时应该显示问号。看来你正在做相反的事情,所以它应该写像“÷”这样的东西。我想这是一个控制台问题,包括用 UTF(再次)将 strace 转换为 ISO 的东西。
  • 不,不是。为什么 UTF-8 字节应显示为八进制转义符而 latin1 字节不显示?正如我所说,strace 在字节级别上工作。否则对二进制数据就没用了。
  • "aaa\u00C3\u00A4" 并不代表您认为的意思。它代表五个字符,而不是五个字节。文件名只有四个字符长。 "aaa\u00E4" 是正确的。
  • 我特意选择了"aaa\u00C3\u00A4"这个例子,我知道它代表的是字符串aaaä。我选择它是为了在我设置LC_ALL=en_US.ISO-8859-1 的测试用例中它可能已被翻译为aaaä
【解决方案2】:

【讨论】:

  • 那篇文章似乎没有给出解决方案,但是,在那里回答问题时,我的答案总是 UTF-8
猜你喜欢
  • 2012-11-17
  • 1970-01-01
  • 1970-01-01
  • 2011-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-30
相关资源
最近更新 更多