为什么java.lang.StringEncoding.encode会忽略给定的字符集而使用默认的字符集?

4
我的应用程序默认编码设置为"UTF-8"(在启动时使用-Dfile.encoding=UTF-8)。 当我使用String类方法“getBytes(String charsetName)”并将charset设置为“ISO-8859-1”时,似乎StringCoding.encode最终使用默认编码(UTF-8)而不是给定的编码(ISO-8859-1)。
由于某种未知原因,我可以逐步调试此方法,但无法检查内部元素的值(仅命名为arg0、arg1等的参数)。
在Java 1.6.10中,StringCoding.encode的写法如下:
static byte[] encode(String charsetName, char[] ca, int off, int len)
    throws UnsupportedEncodingException
{
    StringEncoder se = (StringEncoder)deref(encoder);
    String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
    if ((se == null) || !(csn.equals(se.requestedCharsetName())
                  || csn.equals(se.charsetName()))) {
        se = null;
        try {
        Charset cs = lookupCharset(csn);
        if (cs != null)
            se = new StringEncoder(cs, csn);
        } catch (IllegalCharsetNameException x) {}
        if (se == null)
            throw new UnsupportedEncodingException (csn);
        set(encoder, se);
    }
    return se.encode(ca, off, len);
}

通过逐步调试,我从未进入if块,因此没有使用我的ISO-8859-1字符集创建新的StringEncoder。最后,调用了Charset.defaultCharset()方法。

有什么线索吗? 谢谢


1
“-Dfile.ecoding=UTF-8” 确实是这样拼写吗?如果是,应该改为 “-Dfile.encoding=UTF-8”。 - stark
您能够提供一个完整的例子(SSCCE),展示这种情况吗? - Paŭlo Ebermann
3个回答

3
如果您无法进入 if 代码块,那么这个表达式一定是假的。
(se == null) || !(csn.equals(se.requestedCharsetName())
                  || csn.equals(se.charsetName()))

这意味着:
- `se` 不能为空 - 在遇到 `!` 前第二部分必须为 `true`,因此其中一个子表达式必须为 `true`: - `csn.equals(se.requestedCharsetName())` - `csn.equals(se.charsetName())`
换句话说,`se` 已经适用于您请求的字符集名称。
这不是使用 VM 的“默认”编码方式,而是使用此线程中最后一次使用的编码器。
我非常怀疑您已经发现了 JRE bug - 对我来说看起来还好。那么是什么导致您开始进行调试的呢?您能提供一个简短但完整的程序,演示使用此错误的情况吗?某些编码为错误字节?

@Redmat:这意味着您的字符串中有一些字符无法在ISO-8859-1中表示,这是完全可行的... - Jon Skeet
如果我尝试在我的功能中使用UTF-8字符集,我会得到EFBFBD字节。如果我将file.encoding更改为ISO-8859-1,则它可以完美地工作(但我必须使其在此属性设置为UTF-8时工作)。 - Redmat
我也是这么想的,但我无法找出问题所在。 - Redmat
我也这么认为,但我无法确定在哪里。输入字符串来自xml文件。在我的ByteArrayOutputStream中,我还写入了一些byte[],这些byte[]是通过将“十六进制字符串”转换为byte[]获得的。所谓的“十六进制字符串”,是指十六进制字节的字符串表示(例如,“5649534120454C”被转换为byte[] {0x56,0x49,0x53,0x41,0x20,0x45,0x4C})。 - Redmat
谢谢您的帮助和时间,我会进一步调查,并回来提供更多解释。 - Redmat
显示剩余8条评论

0

编码过程中不应忽略给定的字符集,以恢复到-Dfile.encoding中给定的字符集。

实际上确实会这样做。顺便说一下,即使源代码显示它找到了字符集并在该行中设置了它,解码也会这样做。

set(encoder, se);

encode和decode都不是线程安全的,所以该值很可能被系统默认值覆盖,无论decode何时使用设置的值之前或之后都可能发生。

我认为这是JRE中的一个bug。尽管OP犯了一个错别字,但如果您请求String将一个字节数组解码为UTF-8,它应始终返回UTF-8,而不是悄悄地回退到其他东西。


0
你需要将以下代码中的

-Dfile.ecoding=UTF-8

改为

-Dfile.encoding=UTF-8


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接