设置缺省 Java 字符编码

Setting the default Java character encoding

提问人: 提问时间:12/12/2008 最后编辑:Willi Mentzel 更新时间:12/8/2021 访问量:826388

问:

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

我读过这曾经是旧 JVM 的必经之路。我没有那么奢侈,因为我不会进入的原因。-Dfile.encoding=whatever

我试过:

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

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

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());
Java UTF-8 字符编码

评论

0赞 12/12/2008
优秀的评论伙计们 - 以及我自己已经在想的事情。不幸的是,有一个我无法控制的底层 String.getBytes() 调用。我目前看到的解决它的唯一方法是以编程方式设置默认编码。还有其他建议吗?
7赞 igor.beslic 5/30/2011
也许无关紧要的问题,但是,当 UTF8 设置为“UTF8”、“UTF-8”或“utf8”时,是否有区别。最近,我发现 IBM WAS 6.1 EJB 和 WEB 容器以不同的方式处理(区分大小写)用于定义编码的字符串。
5赞 McDowell 3/25/2012
不支持设置或读取属性。file.encoding
7赞 Christophe Roussy 3/22/2012
只是一个细节,但是:更喜欢 UTF-8 而不是 UTF8(只有前者是标准的)。这在2012年仍然适用......
0赞 overexchange 12/21/2014
@erickson 我仍然不清楚查询,当使用基于字符的 I/O 流(& 的所有子类)时,“file.encoding”是否相关?因为是基于字节的 I/O 流,那么为什么要关心基于字节的 I/O 流中的字符集呢?class Readerclass Writerclass FileInputStream

答:

20赞 Marc Novakowski 12/12/2008 #1

我无法回答你最初的问题,但我想给你一些建议——不要依赖JVM的默认编码。最好在代码中显式指定所需的编码(即“UTF-8”)。这样一来,您就知道它甚至可以在不同的系统和 JVM 配置中工作。

评论

9赞 Michael Borgwardt 3/11/2009
当然,如果你正在编写一个桌面应用程序并处理一些没有任何编码元数据的用户指定的文本,那么平台默认编码是你对用户可能使用的内容的最佳猜测。
0赞 Raedwald 2/10/2012
@MichaelBorgwardt“那么平台默认编码是你最好的猜测”,你似乎在建议想要更改默认值不是一个好主意。您的意思是,尽可能使用显式编码,在没有其他可能的情况下使用提供的 dafault?
1赞 Michael Borgwardt 2/10/2012
@Raedwald:是的,我就是这个意思。平台默认编码是(至少在最终用户计算机上)系统设置为的区域设置中的用户通常使用的编码。如果您没有更好的(即特定于文档的)信息,则应使用这些信息。
1赞 Aleksandr Dubinsky 12/16/2013
@MichaelBorgwardt胡说八道。使用库自动检测输入编码,并使用 BOM 另存为 Unicode。这是处理和对抗编码地狱的唯一方法。
0赞 WesternGun 1/21/2016
我想你们俩不在同一页上。Michael 谈论解码,而 Raedwald 谈论解码后的处理。
40赞 Dov Wasserman 12/12/2008 #2

我认为比设置平台的默认字符集更好的方法是调用更安全的 。这样,您的应用程序就不会依赖于其无法控制的事物。String.getBytes("charsetName")

我个人认为应该弃用它,因为它在我见过的许多情况下都造成了严重的问题,在这些情况下,开发人员没有考虑到默认字符集可能会发生变化。String.getBytes()

评论

0赞 booFar 10/3/2023
是的。默认编码仅用于镜像底层操作系统中设置的区域设置,任何人都不应更改它。如果您不想使用由系统区域设置生成的编码,请始终指定编码。
360赞 erickson 12/12/2008 #3

不幸的是,必须在 JVM 启动时指定该属性;在输入 Main 方法时,已永久缓存 和 使用的字符编码和 的默认构造函数。file.encodingString.getBytes()InputStreamReaderOutputStreamWriter

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

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

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

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

评论

12赞 Stijn de Witt 3/11/2011
为了完整起见,我想补充一点,通过一些技巧,您可以获得实际使用的默认编码(如缓存),这要归功于 Gary Cronin: byte [] byteArray = {'a'};InputStream inputStream = new ByteArrayInputStream(byteArray);InputStreamReader reader = 新 InputStreamReader(inputStream);字符串 defaultEncoding = reader.getEncoding();lists.xcf.berkeley.edu/lists/advanced-java/1999-October/......
2赞 Caspar 8/27/2014
JDK-4163515 提供了有关在 JVM 启动后设置 sysprop 的更多信息。file.encoding
4赞 cabaji99 9/22/2017
我挠了挠头,因为该命令在 Windows、linux 和 mac 上无法完美运行......然后我把“放在值周围,如下所示:java -D”file.encoding=UTF-8“ -jar
0赞 Michail Michailidis 2/24/2018
在Java Spring Boot的情况下检查我的答案:stackoverflow.com/a/48952844/986160
1赞 Dov Wasserman 12/16/2008 #4

目前尚不清楚您在做什么,并且无法控制。如果可以在目标文件上插入不同的 OutputStream 类,则可以使用 OutputStream 的子类型,该子类型将 Strings 转换为您定义的字符集下的字节,例如默认为 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

如果这种方法不可行,如果你在这里明确一下在数据流和执行环境方面可以控制什么和不能控制什么,可能会有所帮助(尽管我知道这有时说起来容易,但确定起来难)。祝你好运。

评论

6赞 Alan Moore 12/25/2008
DataInputStream 和 DataOutputStream 是专用类,绝不能与纯文本文件一起使用。他们使用的修改后的 UTF-8 与真正的 UTF-8 不兼容。此外,如果 OP 可以使用您的解决方案,他也可以使用正确的工具来完成这项工作:OutputStreamWriter。
191赞 dwardu 3/8/2009 #5

来自 JVM™ 工具接口文档...

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

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

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8

评论

0赞 thatidiotguy 8/15/2012
你知道吗,“捡起......”语句会打印在 Tomcat 日志中吗?
1赞 Smaug 2/12/2013
嗨,爱德华·格雷奇,感谢您的解决方案。我在另一个论坛帖子中解决了我的疑问。 stackoverflow.com/questions/14814230/...
1赞 DLight 4/13/2016
@Tiny Java 都理解这两种情况。stackoverflow.com/questions/6031877/......
0赞 lizi 1/20/2012 #6

我们将两个系统属性放在一起,它使系统将所有内容都放入 utf8 中

file.encoding=UTF8
client.encoding.override=UTF-8

评论

8赞 Christophe Roussy 8/20/2012
client.encoding.override 属性似乎是特定于 WebSphere 的。
15赞 Emmanuel.B 1/21/2012 #7

试试这个:

    new OutputStreamWriter( new FileOutputStream("Your_file_fullpath" ),Charset.forName("UTF8"))
80赞 naskoos 2/21/2013 #8

我有一种绝对有效的黑客方式!

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

这样一来,你就会欺骗JVM,JVM会认为charset没有被设置,并让它在运行时再次将其设置为UTF-8!

评论

3赞 SparK 3/14/2013
NoSuchFieldException 对我来说
12赞 Yonatan 8/25/2013
要使黑客攻击起作用,您需要假设安全管理器已关闭。如果您没有办法设置 JVM 标志,那么您可能(可能)还启用了安全管理器的系统。
8赞 dotwin 1/15/2018
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
2赞 sleske 3/8/2018
@Enerccio:这不是一个好的答案,这是一个肮脏的黑客攻击,一个等待发生的问题。这只能作为一项紧急措施。
1赞 sleske 3/8/2018
@Enerccio:Java 是否“应该”有办法设置这一点是有争议的——人们也可以争辩说,开发人员“应该”在相关时明确指定编码。无论如何,从长远来看,这种解决方案可能会造成严重的麻烦,因此需要“仅供紧急使用”的警告。实际上,即使是紧急使用也是值得怀疑的,因为有一种受支持的方法,设置JAVA_TOOL_OPTIONS如另一个答案中所述。
7赞 D Bright 1/9/2014 #9

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

对于遇到此问题的人,以下文章最终帮助我们追踪描述了区域设置如何闯入unicode/UTF-8Java/Tomcat

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

在文件中正确设置区域设置对我们有用。~/.bashrc

7赞 Lavixu 7/3/2014 #10

我已经尝试了很多东西,但这里的示例代码运行完美。链接

代码的关键是:

String s = "एक गाव में एक किसान";
String out = new String(s.getBytes("UTF-8"), "ISO-8859-1");
0赞 LMC 10/5/2017 #11

根据@Caspar接受的答案的评论,根据 Sun 的说法,解决这个问题的首选方法是:

“在启动 Java 程序之前更改底层平台的区域设置。”

http://bugs.java.com/view_bug.do?bug_id=4163515

对于 docker,请参阅:

http://jaredmarkell.com/docker-and-locales/

0赞 midmaestro 10/15/2017 #12

最近,我偶然发现了一家本地公司的 Notes 6.5 系统,发现网络邮件在非中问本地化的 Windows 安装中会显示无法识别的字符。在网上挖了几个星期,几分钟前才想通:

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

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

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

7赞 Michail Michailidis 2/24/2018 #13

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

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

这对我们来说是需要的,因为我们使用的是模板,而操作系统已经通过我们发现了这一点JTwigANSI_X3.4-1968System.out.println(System.getProperty("file.encoding"));

希望这对某人有所帮助!

1赞 prabushi samarakoon 3/6/2018 #14
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)
2赞 Berend Menninga 4/24/2018 #15

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

在 Elastic Beanstalk 中,转到 Configuration > Software 的“环境属性”。 将 (name) JAVA_TOOL_OPTIONS与 (value) -Dfile.encoding=UTF8 相加

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

4赞 JacobTheKnitter 7/3/2019 #16

我的团队在装有 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>
1赞 Febix 8/7/2020 #17

在我的项目中解决这个问题。希望它对某人有所帮助。

我使用 LIBGDX java 框架,在我的 android studio 项目中也遇到了这个问题。 在 Mac OS 中编码是正确的,但在 Windows 10 中,特殊字符和符号以及 此外,俄语字符显示为以下问题:?????和其他不正确的符号。

  1. Android Studio 项目设置更改:所有三个字段(下面的全局编码、项目编码和默认值)都更改为 UTF-8。File->Settings...->Editor-> File Encodings

  2. 在任何 java 文件集中:

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

  3. 对于测试打印调试日志:

    System.out.println("My project encoding is : "+ Charset.defaultCharset());

1赞 theseventhsense 11/5/2021 #18

在启动应用程序时设置 jvm 参数帮助我解决了这个问题。.java -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8

file.encoding=UTF-8- 这有助于在文件中包含Unicode字符。

sun.jnu.encoding=UTF-8- 这有助于将 Unicode 字符作为文件系统中的文件名。