3 回答
TA贡献1830条经验 获得超9个赞
这真的很奇怪......一旦设置,默认的Charset就会被缓存,并且当类在内存中时它不会被更改。设置"file.encoding"
属性System.setProperty("file.encoding", "Latin-1");
不会做任何事情。每次Charset.defaultCharset()
调用它都会返回缓存的字符集。
这是我的结果:
Default Charset=ISO-8859-1file.encoding=Latin-1Default Charset=ISO-8859-1Default Charset in Use=ISO8859_1
我正在使用JVM 1.6。
(更新)
好。我确实用JVM 1.5重现了你的错误。
查看1.5的源代码,未设置缓存的默认字符集。我不知道这是不是一个bug,但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()
,会发生什么,因为未设置缓存的默认字符集,它将尝试为该名称查找相应的字符集Latin-1
。找不到此名称,因为它不正确,并返回默认值UTF-8
。
至于为什么IO类,如OutputStreamWriter
返回一个意外的结果,
执行sun.nio.cs.StreamEncoder
(女巫使用由这些IO类)是不同的,以及对于JVM 1.5和1.6 JVM。JVM 1.6实现基于Charset.defaultCharset()
获取默认编码的方法(如果没有提供给IO类)。JVM 1.5实现使用不同的方法Converters.getDefaultEncodingName();
来获取默认字符集。此方法使用自己的JVM初始化时设置的默认charset缓存:
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);}
但我同意这些意见。你不应该依赖这个属性。这是一个实现细节。
TA贡献1856条经验 获得超17个赞
这是一个错误或功能吗?
看起来像未定义的行为。我知道,在实践中,您可以使用命令行属性更改默认编码,但我不认为定义时执行此操作会发生什么。
错误ID:4153515有关设置此属性的问题:
这不是一个错误。J2SE平台规范不要求“file.encoding”属性; 它是Sun实现的内部细节,不应由用户代码检查或修改。它也是只读的; 在技术上不可能支持在命令行或程序执行期间的任何其他时间将此属性设置为任意值。
更改VM和运行时系统使用的默认编码的首选方法是在启动Java程序之前更改底层平台的区域设置。
当我看到人们在命令行上设置编码时,我感到畏缩 - 你不知道会影响哪些代码。
如果您不想使用默认编码,请通过适当的方法/ 构造函数设置您想要的编码。
添加回答
举报