设置默认的Java字符编码


362

如何以编程方式正确设置JVM(1.5.x)使用​​的默认字符编码?

我读过,这-Dfile.encoding=whatever曾经是使用旧JVM的方法。由于没有理由,我没有那么奢侈。

我努力了:

System.setProperty("file.encoding", "UTF-8");

并设置了属性,但似乎不会导致getBytes下面的最终调用使用UTF8:

System.setProperty("file.encoding", "UTF-8");

byte inbytes[] = new byte[1024];

FileInputStream fis = new FileInputStream("response.txt");
fis.read(inbytes);
FileOutputStream fos = new FileOutputStream("response-2.txt");
String in = new String(inbytes, "UTF8");
fos.write(in.getBytes());

优秀的评论们-我已经在想自己的事情了。不幸的是,有一个我无法控制的底层String.getBytes()调用。我目前看到的唯一解决方法是以编程方式设置默认编码。还有其他建议吗?

6
也许是无关紧要的问题,但是,如果将UTF8设置为“ UTF8”,“ UTF-8”或“ utf8”,会有区别吗?最近,我发现IBM WAS 6.1 EJB和WEB容器对用于定义编码的字符串的区别对待(区分大小写)。
igor.beslic 2011年

5
只是一个细节,但是:与UTF8相比,它更喜欢UTF-8(只有前者​​是标准的)。这在2012年仍然适用...
Christophe Roussy

4
不支持设置或读取file.encoding属性。
McDowell 2012年

@erickson这个查询还是不清楚的,使用基于字符的I / O流(class Reader&的所有子类class Writer)时,“ file.encoding”是否相关,这不是真的吗?因为class FileInputStream是基于字节的I / O流,所以为什么要关心基于字节的I / O流中的字符集?
overexchange 2014年

Answers:


311

不幸的是,file.encoding必须在JVM启动时指定该属性。在您输入main方法时,所使用的字符编码String.getBytes()以及的默认构造函数InputStreamReaderOutputStreamWriter都已被永久缓存。

正如Edward Grech所指出的那样,在这种特殊情况下,JAVA_TOOL_OPTIONS 可以使用环境变量来指定此属性,但通常是这样完成的:

java -Dfile.encoding=UTF-8  com.x.Main

Charset.defaultCharset()将反映对file.encoding属性的更改,但是核心Java库中需要确定默认字符编码的大多数代码都不使用此机制。

在编码或解码时,可以查询file.encoding属性或Charset.defaultCharset()查找当前的默认编码,并使用适当的方法或构造函数重载来指定它。


9
为了完整起见,我想补充一点,由于加里·克罗宁(Gary Cronin)的帮助,您可以使用实际使用的默认编码(就像缓存一样):byte [] byteArray = {'a'};。InputStream inputStream =新的ByteArrayInputStream(byteArray); InputStreamReader reader =新的InputStreamReader(inputStream); 字符串defaultEncoding = reader.getEncoding(); list.xcf.berkeley.edu/lists/advanced-java/1999-October/…–
Stijn de Witt

2
JDK-4163515提供了file.encoding有关在JVM启动后设置sysprop的更多信息。
卡斯珀2014年

2
我挠头,原因是该命令无法在Windows,Linux和Mac上完美运行...然后我将“值”放在这样的位置:java -D“ file.encoding = UTF-8” -jar
cabaji99

在Java Spring Boot的情况下检查我的答案:stackoverflow.com/a/48952844/986160
Michail Michailidis

170

JVM™工具界面文档中…

由于命令行不能始终被访问或修改,例如在嵌入式VM或仅在脚本内部深层启动的VM中,JAVA_TOOL_OPTIONS因此提供了一个变量,以便在这种情况下可以启动代理。

通过将(Windows)环境变量设置JAVA_TOOL_OPTIONS-Dfile.encoding=UTF8System将在每次启动JVM时自动设置(Java)属性。您将知道参数已被选取,因为以下消息将发布到System.err

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8


您是否知道在Tomcat日志中会打印“ Picked up ...”语句?
thatidiotguy 2012年

1
嗨,爱德华·格雷奇,谢谢您的解决方案。我在另一个论坛帖子中的疑问已解决。stackoverflow.com/questions/14814230/…–
Smaug

8
UTF8还是UTF-8
微型


您的解决方案节省了我的时间,非常感谢!
Sobhan

67

我有一个绝对可行的技巧!

System.setProperty("file.encoding","UTF-8");
Field charset = Charset.class.getDeclaredField("defaultCharset");
charset.setAccessible(true);
charset.set(null,null);

这样,您将欺骗那些认为未设置字符集的JVM,并使其在运行时再次将其设置为UTF-8!


2
对我来说
NoSuchFieldException

10
为了使黑客工作,您需要假设安全管理器已关闭。如果您没有办法设置JVM标志,则可能(也可能)具有启用了安全管理器的系统。
Yonatan

3
JDK9 不再认可此黑客。WARNING: An illegal reflective access operation has occurred • WARNING: Illegal reflective access by [..] • WARNING: Please consider reporting this to the maintainers of [..] • WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations • WARNING: All illegal access operations will be denied in a future release
dotwin

1
@Enerccio:这不是一个好答案,这是一个肮脏的hack,还有一个等待发生的问题。那只能用作紧急措施。
sleske

1
@Enerccio:Java是否“应该”设置此方法是有争议的–人们还可能认为,开发人员“应该”在相关时明确指定编码。无论如何,从长远来看,该解决方案有可能造成严重的麻烦,因此需要“仅供紧急使用”。其实,即使紧急情况下使用是有问题的,因为那里做这件事的支持方式,设置JAVA_TOOL_OPTIONS作为另一个答案解释。
sleske

38

我认为,比设置平台的默认字符集更好的方法,尤其是在您似乎对影响应用程序部署有限制的情况下,更不用说平台了,这是更安全的方法String.getBytes("charsetName")。这样,您的应用程序就不会依赖超出其控制范围的事物。

我个人认为String.getBytes()应该弃用该方法,因为在我所看到的许多情况下,它引起了严重的问题,在这些情况下,开发人员并未考虑可能更改的默认字符集。


18

我无法回答您的原始问题,但是我想向您提供一些建议-不要依赖JVM的默认编码。始终最好在代码中明确指定所需的编码(即“ UTF-8”)。这样,您知道它甚至可以在不同的系统和JVM配置中运行。


7
当然,除了要编写桌面应用程序并处理一些用户指定的,没有任何编码元数据的文本外,平台默认编码是用户可能会使用的最佳猜测。
Michael Borgwardt

@MichaelBorgwardt“然后,平台默认编码是您的最佳猜测”,您似乎建议要更改默认值并不是一个好主意。您是说,在无其他可能的情况下,使用提供的dafault尽可能使用显式编码?
拉德瓦尔德

1
@Raedwald:是的,这就是我的意思。平台默认编码是(至少在最终用户计算机上)系统设置为在区域设置中通常使用的用户。如果没有更好的信息(即特定于文档的信息),则应使用该信息。
Michael Borgwardt'2

1
@MichaelBorgwardt废话。使用一个库来自动检测输入编码,并使用BOM将其另存为Unicode。那是应对和对抗编码地狱的唯一方法。
Aleksandr Dubinsky

我认为你们两个不在同一页面上。Michael谈论解码,而Raedwald谈论解码后的处理。
WesternGun

12

尝试这个 :

    new OutputStreamWriter( new FileOutputStream("Your_file_fullpath" ),Charset.forName("UTF8"))

5

我们遇到了同样的问题。我们有条不紊地尝试了本文(和其他文章)中的一些建议,但均无济于事。我们还尝试添加-Dfile.encoding=UTF8,但似乎没有任何效果。

对于那些有这个问题的人,下面的文章终于帮我们追查介绍了区域设置如何打破unicode/UTF-8Java/Tomcat

http://www.jvmhost.com/articles/locale-breaks-unicode-utf-8-java-tomcat

~/.bashrc文件中正确设置语言环境对我们有用。


4

我已经尝试了很多事情,但是这里的示例代码非常完美。 链接

代码的关键是:

String s = "एक गाव में एक किसान";
String out = new String(s.getBytes("UTF-8"), "ISO-8859-1");

4

如果您使用的是Spring Boot,并且想file.encoding在JVM中传递参数,则必须像这样运行它:

mvn spring-boot:run -Drun.jvmArguments="-Dfile.encoding=UTF-8"

这是我们需要的,因为我们使用的是JTwig模板,而操作系统则ANSI_X3.4-1968通过System.out.println(System.getProperty("file.encoding"));

希望这对某人有帮助!


2

我正在使用Amazon(AWS)Elastic Beanstalk,并将其成功更改为UTF-8。

在Elastic Beanstalk中,转到“配置”>“软件”,“环境属性”。添加(名称)JAVA_TOOL_OPTIONS和(值)-Dfile.encoding = UTF8

保存后,环境将以UTF-8编码重新启动。


1

目前尚不清楚您做什么,也没有控制权。如果可以在目标文件上插入不同的OutputStream类,则可以使用OutputStream的子类型,该子类型将字符串转换为您定义的字符集下的字节,默认情况下为UTF-8。如果修改后的UTF-8足以满足您的需求,则可以使用DataOutputStream.writeUTF(String)

byte inbytes[] = new byte[1024];
FileInputStream fis = new FileInputStream("response.txt");
fis.read(inbytes);
String in = new String(inbytes, "UTF8");
DataOutputStream out = new DataOutputStream(new FileOutputStream("response-2.txt"));
out.writeUTF(in); // no getBytes() here

如果这种方法不可行,那么如果您在此处明确说明可以控制和不能控制的数据流和执行环境,可能会有所帮助(尽管我知道有时说起来容易做起来难,但要确定)。祝好运。


5
DataInputStream和DataOutputStream是专用类,绝对不能与纯文本文件一起使用。他们采用的修改后的UTF-8与真正的UTF-8不兼容。此外,如果OP可以使用您的解决方案,那么他也可以使用正确的工具完成此工作:OutputStreamWriter。
艾伦·摩尔

1
mvn clean install -Dfile.encoding=UTF-8 -Dmaven.repo.local=/path-to-m2

该命令与exec-maven-plugin配合使用,可在配置jenkins任务时解决以下错误。

Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512m; support was removed in 8.0
Error occurred during initialization of VM
java.nio.charset.IllegalCharsetNameException: "UTF-8"
    at java.nio.charset.Charset.checkName(Charset.java:315)
    at java.nio.charset.Charset.lookup2(Charset.java:484)
    at java.nio.charset.Charset.lookup(Charset.java:464)
    at java.nio.charset.Charset.defaultCharset(Charset.java:609)
    at sun.nio.cs.StreamEncoder.forOutputStreamWriter(StreamEncoder.java:56)
    at java.io.OutputStreamWriter.<init>(OutputStreamWriter.java:111)
    at java.io.PrintStream.<init>(PrintStream.java:104)
    at java.io.PrintStream.<init>(PrintStream.java:151)
    at java.lang.System.newPrintStream(System.java:1148)
    at java.lang.System.initializeSystemClass(System.java:1192)

0

我们在那里设置了两个系统属性,这使系统将所有内容都放入utf8

file.encoding=UTF8
client.encoding.overrideUTF-8

7
client.encoding.override属性似乎是特定于WebSphere的。
Christophe Roussy 2012年


0

最近,我碰到了本地公司的Notes 6.5系统,发现该Webmail在非Zhongwen本地Windows安装中会显示无法识别的字符。在网上挖了几周,几分钟前就发现了:

在Java属性中,将以下字符串添加到“运行时参数”

-Dfile.encoding=MS950 -Duser.language=zh -Duser.country=TW -Dsun.jnu.encoding=MS950

在这种情况下,UTF-8设置将不起作用。


0

我的团队在装有Windows的计算机中遇到了相同的问题。.然后设法通过两种方式解决了该问题:

a)设置环境变量(即使在Windows系统首选项中)

JAVA_TOOL_OPTIONS
-Dfile.encoding = UTF8

b)在您的pom.xml中引入以下代码段:

 -Dfile.encoding=UTF-8 

 <jvmArguments>
 -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8001
 -Dfile.encoding=UTF-8
 </jvmArguments>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.