当前位置: 首页 > 面试题库 >

如何在Java中查找默认的字符集/编码?

晏富
2023-03-14
问题内容

显而易见的答案是使用,Charset.defaultCharset()但是我们最近发现这可能不是正确的答案。有人告诉我,结果在某些情况下不同于java.io类使用的实际默认字符集。看起来Java保留了2套默认字符集。有人对这个问题有见解吗?

我们能够重现一个失败案例。这是一种用户错误,但仍可能会暴露所有其他问题的根本原因。这是代码,

public class CharSetTest {

    public static void main(String[] args) {
        System.out.println("Default Charset=" + Charset.defaultCharset());
        System.setProperty("file.encoding", "Latin-1");
        System.out.println("file.encoding=" + System.getProperty("file.encoding"));
        System.out.println("Default Charset=" + Charset.defaultCharset());
        System.out.println("Default Charset in Use=" + getDefaultCharSet());
    }

    private static String getDefaultCharSet() {
        OutputStreamWriter writer = new OutputStreamWriter(new ByteArrayOutputStream());
        String enc = writer.getEncoding();
        return enc;
    }
}

我们的服务器要求使用Latin-1中的默认字符集来处理传统协议中的某些混合编码(ANSI / Latin-1 / UTF-8)。因此,我们所有的服务器都使用此JVM参数运行,

-Dfile.encoding=ISO-8859-1

这是Java 5的结果

Default Charset=ISO-8859-1
file.encoding=Latin-1
Default Charset=UTF-8
Default Charset in Use=ISO8859_1

有人尝试通过在代码中设置file.encoding来更改编​​码运行时间。我们都知道那是行不通的。但是,这显然会抛出defaultCharset(),但不会影响OutputStreamWriter使用的实际默认字符集。

这是错误还是功能?

编辑:接受的答案显示了问题的根本原因。基本上,您不能信任Java 5中的defaultCharset(),它不是I / O类使用的默认编码。看起来Java 6可以解决此问题。


问题答案:

这真的很奇怪。。。一旦设置,默认的Charset将被缓存,并且当类在内存中时不会更改。将"file.encoding"属性设置为System.setProperty("file.encoding", "Latin-1");无。每次Charset.defaultCharset()调用时,它都会返回缓存的字符集。

这是我的结果:

Default Charset=ISO-8859-1
file.encoding=Latin-1
Default Charset=ISO-8859-1
Default Charset in Use=ISO8859_1

我正在使用JVM 1.6。

(更新)

好。我确实使用JVM 1.5重现了你的错误。

查看源代码1.5,未设置缓存的默认字符集。我不知道这是否是一个错误,但是1.6更改了此实现并使用了缓存的字符集:

JVM 1.5:

public static Charset defaultCharset() {
    synchronized (Charset.class) {
        if (defaultCharset == null) {
            java.security.PrivilegedAction pa =
                    new GetPropertyAction("file.encoding");
            String csn = (String) AccessController.doPrivileged(pa);
            Charset cs = lookup(csn);
            if (cs != null)
                return cs;
            return forName("UTF-8");
        }
        return defaultCharset;
    }
}

JVM 1.6:

public static Charset defaultCharset() {
    if (defaultCharset == null) {
        synchronized (Charset.class) {
            java.security.PrivilegedAction pa =
                    new GetPropertyAction("file.encoding");
            String csn = (String) AccessController.doPrivileged(pa);
            Charset cs = lookup(csn);
            if (cs != null)
                defaultCharset = cs;
            else
                defaultCharset = forName("UTF-8");
        }
    }
    return defaultCharset;
}

当你将文件编码设置file.encoding=Latin-1为下次调用时Charset.defaultCharset(),会发生这种情况,因为未设置缓存的默认字符集,它将尝试为name查找合适的字符集Latin-1。找不到此名称,因为它不正确,并返回default UTF-8。

至于诸如此类的IO类为何OutputStreamWriter返回意外结果的原因,对于JVM 1.5和JVM 1.6
sun.nio.cs.StreamEncoder(这些IO类使用巫婆的)实现也有所不同。Charset.defaultCharset()如果未为IO类提供默认编码,则JVM 1.6实现基于该方法来获取默认编码。JVM 1.5实现使用另一种方法Converters.getDefaultEncodingName();来获取默认字符集。此方法使用自己的默认字符集缓存,该缓存是在JVM初始化时设置的:

JVM 1.6:

public static StreamEncoder forOutputStreamWriter(OutputStream out,
        Object lock,
        String charsetName)
        throws UnsupportedEncodingException
{
    String csn = charsetName;
    if (csn == null)
        csn = Charset.defaultCharset().name();
    try {
        if (Charset.isSupported(csn))
            return new StreamEncoder(out, lock, Charset.forName(csn));
    } catch (IllegalCharsetNameException x) { }
    throw new UnsupportedEncodingException (csn);
}

JVM 1.5:

public static StreamEncoder forOutputStreamWriter(OutputStream out,
        Object lock,
        String charsetName)
        throws UnsupportedEncodingException
{
    String csn = charsetName;
    if (csn == null)
        csn = Converters.getDefaultEncodingName();
    if (!Converters.isCached(Converters.CHAR_TO_BYTE, csn)) {
        try {
            if (Charset.isSupported(csn))
                return new CharsetSE(out, lock, Charset.forName(csn));
        } catch (IllegalCharsetNameException x) { }
    }
    return new ConverterSE(out, lock, csn);
}

但是我同意这些意见。你不应该依赖此属性。这是一个实现细节。



 类似资料:
  • 问题内容: 如何设置默认的Java字符编码? 问题答案: 必须在JVM启动时指定该属性。通过输入你的主要方法时,编码中使用的字符由和默认的构造函数,并已被永久缓存。 在特殊情况下, 可以使用环境变量来指定此属性,但通常是这样完成的: 将反映对属性的更改,但是核心Java库中需要确定默认字符编码的大多数代码都不使用此机制。 在编码或解码时,可以查询属性或查找当前的默认编码,并使用适当的方法或构造函数

  • 问题内容: 如何通过编程正确设置JVM(1.5.x)使用​​的默认字符编码? 我读过,这-曾经是使用旧JVM的方法。由于没有理由,我没有那么奢侈。 我试过了: 并且该属性被设置,但似乎不会导致下面的最终调用使用UTF8: 问题答案: 不幸的是,必须在JVM启动时指定该属性。通过输入你的主要方法时,编码中使用的字符由和默认的构造函数,并已被永久缓存。 正如指出的那样,在这种特殊情况下, 可以使用环境

  • 问题内容: 在我的应用程序中,我从LDAP获取用户信息,有时完整的用户名使用了错误的字符集。例如: 它也可以是英语或俄语,并可以正确显示。如果用户名更改,它将在数据库中更新。即使我更改数据库中的值,它也无法解决问题。 我可以在保存之前修复此问题 但是,如果我将它用于包含俄语字符的字符串(例如,“Тест61Тестович61”),则会得到类似“ ??? 61 ??????? 61”的信息。 您能

  • 我正在尝试将AEM/Sling使用的字符编码设置为UTF-8。根据Sling文档,这可以被Sling主servlet上的属性覆盖: 从Sling Engine 2.2.4开始,请求参数是可选的。从这个版本开始,Sling Main Servlet支持一个配置设置,允许在请求参数丢失时更改所使用的默认字符编码。 null

  • 问题内容: 我正在用Java编程 我的代码为: 在api中指定,如果不指定字符编码,它将采用默认的平台字符编码。 “默认平台字符编码”是什么意思? 它是Java编码还是OS编码? 如果这意味着操作系统编码,如何检查Windows和Linux的默认字符编码?无论如何,我们可以使用命令行获取默认的字符编码吗? 问题答案: 这表示您正在运行的JVM的默认字符编码, 要检查默认编码,您可以执行以下操作:

  • 问题内容: 有一个MySQL 具有以下定义: 我想将此表的更改为。怎么做 ? 问题答案: 如果要将表和所有字符列更改为新字符集,请使用如下语句: 因此查询将是: