赞
踩
一、前言
编码配置原则
源码文件用于项目组之间进行版本控制, 一般用UTF-8
日志文件可能会用于在各个平台上查看, 一般用UTF-8
控制台编码对接你的电脑系统编码, 一般电脑默认是GBK
因为我的电脑是Window10默认编码是GBK, 所以我控制台配置主打GBK
我的编码配置
IDEA中 idea64.exe.vmoptions 中的 -Dfile.encoding 和 -Dconsole.encoding 的相关配置全部去除掉, 使用系统默认GBK即可.
这个使用系统默认即可, 没必要一乱码就改这个, 你的乱码往往不是这个原因.
Run/Debug Configurations 中的 -Dfile.encoding 全部去除掉, 使用系统默认GBK即可.
这个地方和上面 idea64.exe.vmoptions配置的都是VM这个参数, 这个比上面那个优先级更高,和上面的原因一样, JDK默认的已经很好了, 不需要配置这个
这个地方会影响到控制台log日志, 以及文件日志编码, 但是未必一定要配置为UTF-8编码, 使用默认即可, 具体原因下面会讲
=注意==
在你的项目中加上一句下面的代码, 看下打印的结果.
System.out.println(System.getProperty(“file.encoding”));
如果此时打印的是GBK, 那么下面的控制台默认编码就是GBK.
如果此时打印的是UTF-8, 那么下面的控制台默认编码就是UTF-8.
之前使用IDEA2018, 2019的时候, 下面的结果应该是GBK, 但是用2020的时候, 有时却莫名其妙变成了UTF-8,
tomcat路径下, \conf\logging.properties配置, 注意和控制台有关的Handler:java.util.logging.ConsoleHandler.encoding 改为第3步file.encoding输出的编码, 其它和文件有关的Handler全部UTF-8
############################################################ # Handler specific properties. # Describes specific configuration info for Handlers. ############################################################ 1catalina.org.apache.juli.AsyncFileHandler.level = FINE 1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs 1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina. 1catalina.org.apache.juli.AsyncFileHandler.encoding = UTF-8 2localhost.org.apache.juli.AsyncFileHandler.level = FINE 2localhost.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs 2localhost.org.apache.juli.AsyncFileHandler.prefix = localhost. 2localhost.org.apache.juli.AsyncFileHandler.encoding = UTF-8 3manager.org.apache.juli.AsyncFileHandler.level = FINE 3manager.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs 3manager.org.apache.juli.AsyncFileHandler.prefix = manager. 3manager.org.apache.juli.AsyncFileHandler.encoding = UTF-8 4host-manager.org.apache.juli.AsyncFileHandler.level = FINE 4host-manager.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs 4host-manager.org.apache.juli.AsyncFileHandler.prefix = host-manager. 4host-manager.org.apache.juli.AsyncFileHandler.encoding = UTF-8 java.util.logging.ConsoleHandler.level = FINE java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter java.util.logging.ConsoleHandler.encoding = GBK 12345678910111213141516171819202122232425262728
因为一般web项目都是用到了tomcat, 因此tomcat也需要配置, 但实际上这个配置影响的只是tomcat相关的log文件
至于这个地方为什么网上大多都是 GBK? 请往下看, 下面有解释
正确配置log配置文件编码(重要)
终于到了我们最重要的环节, 我想说的是99%的乱码问题都是我们log配置文件没有配置好导致的, 结果大家不去改log配置文件, 偏偏盯上VM配置, 和tomcat配置.
我想告诉大家的是, 人家IDEA, tomcat, JDK的默认配置明明已经很好了, 我们应该去适应人家, 而不是修改人家的默认配置来适应我们五花八门的log配置文件,
例如:
A的log配置的有问题, 导致IDEA控制台乱码了, 他修改了IDEA, tomcat, JDK配置, 成功强迫IDEA, tomcat, JDK配置适应它的他配置, 最终成功正确输出日志,
之后B的log配置的也有问题, 日志也乱码了, 然后他参照A的配置配置之后, 发现乱码问题依然没有解决,
要知道这个项目一个log配置, 那个项目一个log配置, 还有的log框架都不一样, 就算要强迫IDEA, tomcat, JDK适应我们的log配置文件, 由于我们的log配置文件不一样, 对应的被强迫的IDEA, tomcat, JDK配置也是不一样的
因此为了统一配置方式, IDEA, tomcat, JDK 配置使用默认即可, 由我们的log配置来适应它们.
下面是我的 log4j2.xml 部分示例配置, 如果你用的是log4j或logback或其它, 就参照相对的log框架的Appenders配置方法
这里我为每个Appender 配置一下输出编码, 和控制台有关的:Console:charset 改为第3步file.encoding输出的编码, 其它和文件有关的RollingFile全部设置为**UTF-8****
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="DEBUG"> <Appenders> <!--这个输出控制台的配置,这里输出除了warn和error级别的信息到System.out --> <Console name="Console" target="SYSTEM_OUT" follow="true"> <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" /> <!-- 输出日志的格式 --> <PatternLayout charset="GBK" pattern="%m%n" /> </Console> <!-- 同一来源的Appender可以定义多个RollingFile,定义按天存储日志 --> <RollingFile name="rolling_file" fileName="${logDir}/dust-server.log" filePattern="${logDir}/dust-server_%d{yyyy-MM-dd}.log"> <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" /> <!-- 输出日志的格式 --> <PatternLayout charset="UTF-8" pattern="%m%n" /> </RollingFile> </Appenders> <Loggers> <Root level="all"> <AppenderRef ref="Console"/> <AppenderRef ref="rolling_file"/> </Root> </Loggers> </Configuration> 12345678910111213141516171819202122232425
另外说一下几个重要但是和乱码无关的配置
项目配置
这个地方挺重要的, 它控制着你整个项目java 文件编码, 配置文件编码, 新建文件编码.
但是它和你的控制台乱码是毫无关系的, 就算你将这里的编码配置改成UTF-3.1415926, 它也管不到你的日志乱码
可能有很多人对上面的配置不理解 请继续往下看.
二、乱码原因
首先我们要知道什么是乱码, 简而言之乱码就是文件打开的编码方式和文件本身编码方式不对, 注意这个地方有两个编码, 一个是文件本身的编码, 一个是用什么编码打开文件, 两个编码不对应, 就会出现乱码.
例如以下图片(控制台乱码)
关于这个 淇℃伅, 我可以明确告诉你们这个是UTF-8编码信息, 那为什么会显示成淇℃伅呢, 是因为控制台以 GBK的方式显示UTF-8编码.
图片中的控制台乱码中的日志一般有两种, 一个是 tomcat 输出日志到控制台, 另一个是 jvm 输出日志到控制台., 网上关于解决控制台乱码的方法大都是 修改 jvm 输出日志编码 和 tomcat 输出日志编码, 但是却忽视了一个重要的编码, 那就是 控制台是以什么编码方式显示信息的呢?.
关于这点我可以告诉你们, 一般来说, 中国电脑系统默认编码是 GBK, IDEA 控制台显示的编码也是 GBK.
现在是不是已经明白了, 也就是说控制台以 GBK 的方式打开了 tomcat 和 JVM 输出的 UTF-8 编码, 那不乱码才怪.
三、深入分析乱码原理
编码 解释
GBK 汉字内码扩展规范, 向下与 GB 2312 编码兼容,向上支持 ISO 10646.1国际标准,window中国区默认编码
UTF-8 针对Unicode的一种可变长度字符编码。兼容于ASCII编码, 国际比较通用的编码格式
在一些编译器里面也许有 ANSI 这种编码, 但实际上 ANSI 并不是特指某一种具体的编码, 这里以window为例, 假如你window电脑的区域和语言是中国, 那么“ANSI编码”实际是GBK编码。当你把它改成Korean(Korea)时,“ANSI编码”实际是EUC-KR编码,当你把它改成English(US)时,“ANSI编码”实际是ASCII编码.
UTF-16 是JDK String 的存储编码, 但一般来说, 你只要不对char数组进行bit解析, 至少你在日志中一般不会碰到UTF-16的情况.
综上分析, 我们只需要研究下GBK 和 UTF-8 两种编码格式即可.
2. 其次让我们分析下JAVA IDEA开发中涉及到的编码配置可能有哪些
列举所有可能出现的情况大概就以下几种, 先别管对不对, 只要可能的就先列举上
1. java 源文件编码.
2. java编译成的class文件编码.
3. jvm 以什么编码格式运行class文件.
4. jvm 以什么方式输出日志
5. 控制台以什么编码格式显示输出日志.
6. 系统默认编码
7. log 日志输出编码(log4j, log4j2, logback).
四、接下来让我们通过问答的方式大家明白几个解释起来比较散乱的常识
Q1: java 源代码会对乱码有影响吗
A: 源文件编码格式对乱码没什么影响
事实上不管你 java 源代码用的是什么编码格式, 编译成的 class 文件都是一样的, 而class文件编码貌似只有一种, 盲猜应该是UTF-16.
下面是我将内容同样而编码格式不同的两份源码编译成的两个class文件属性图, 通过文件算码发现两个class文件完全一致.
所以那些一乱码就乱改文件格式的行为实际上对乱码是没有什么帮助的
Q2: -Dfile.encoding到底是什么
在命令行中输入 java,在给出的提示中会出现 -D 的说明:
-D<name>=<value> # set a system property
1
也就是说 -D 后面需要跟一个键值对,作用是设置一项系统属性
-Dfile.encoding=UTF-8 来说就是设置系统属性 file.encoding 为 UTF-8
Q3: file.encoding到底是有什么用
JVM 在运行时有一个属性 file.encoding, 这个 file.encoding 的值, 默认是系统编码(中国大陆window系统编码默认是GBK), 但是如果在JVM启动时加一个参数 -Dfile.encoding=UTF-8, 那么获取 file.encoding 的值就变成了UTF-8,
这个file.encoding可重要了, 它不仅控制着JVM运行时的编码格式, 还控制着 System.out.println() 打印到控制台的输出编码格式, 而且类似于IDEA这类IDE在显示控制台的时候还会通过 file.encoding 确定控制台用什么编码来解析日志.
关于file.encoding, 在java代码中获取它的值的代码是 System.getProperty("file.encoding") 或 Charset.defaultCharset().name().
在此说一个题外话, 例如在项目启动处, 例如Springboot启动处添加一句下面的代码对乱码时的解决是很有帮助的.
log.info("file.encoding: {}", System.getProperty("file.encoding"));
Q4: console.encoding 是什么
关于这个实际上可以在IDEA 官网看到这样的内容
翻译成中文就是
然而我照着上面试过之后发现, 无论我怎么添加配置后重启, 最终都没什么卵用, 为此这几天我特意将IDEA从2019.3.3升级到了2020.3, 但是发现还是没什么用, 最终决定控制台输出编码的还是file.encoding, 如果有小伙伴知道, 这个有什么用的话, 欢迎留言
Q5: log 日志配置对乱码有影响吗
A:关于log日志, 我只想说的就是, 日常90%的乱码都是因为log日志没有配置好而引起的.
绝大多数日志乱码情况下, 大家都是去改IDEA配置, 改 file.encoding, 但事实上是 IDEA 配置是没有问题的,
即便你的配置有些小问题, java语言和IDEA的智能性也能帮你显示成正确的编码, 然后大家的处理方式就成了 明明是Log日志配置不对,
却偏偏去改IDEA配置, 致使IDEA去适应log, 这样即使最后显示正确的编码, 实际上也是没有灵魂的.
首先我想说明一点, log4j 实际上是有很多问题的, 例如就有版本问题和各种乱码问题.
而且 log4j 比较恶心的是有些版本默认输出编码格式遵循 file.encoding, 还有的默认 系统编码格式, 也就是说, 有些垃圾版本即便你改了file.encoding=UTF-8也没用, 它依然遵循系统默认GBK编码.
而且都什么年代了, 别用log4j了, 换 log4j2 吧
Q6: log配置文件中编码如何配置(以log4j2 配置为例)
A: 以log4j2 配置为例, 如下图配置文件, 从上至下, 让我们一个个解析
首先第一个 encoding, 这个 encoding 跟你的乱码一般没什么关系的, 它管理的是 log 配置文件的编码格式, 也就是说它管理的是日志插件以什么格式去解析log4j2.xml, 这个配置文件.
知道Html吧, 第一个encoding和html文件标题头上面的 encoding 是类似的.
关于这个地方有个小Tip, 例如在IDEA里面, 只要你把文件头的这个encoding从GBK改成UTF-8,
然后IDEA就会自然的把你整个文件的编码格式给改成UTF-8了.
如上图中的2处和3处的****, 这个配置管理的才是输出到你的控制台或者是文件的编码, 当然你也可以写成
<PatternLayout charset="GBK" pattern="%m%n" />
注意这个配置是log4j2的配置, 如果你使用的是[log4j]或者是logback, 请在网上搜索相应的编码配置.
五、解决方式
既然如此, 那么解决方案就很明确了, 无非两种
**(不推荐)**修改 IDEA 控制台显示编码为 UTF-8, 以及 tomcat, jvm 输出的日志编码也修改为 UTF-8;
toncat 安装路径下的 conf/logging.properties 配置文件中的
java.util.logging.ConsoleHandler.encoding 改成 UTF-8;jvm 启动参数 VM options 加个配置 -Dfile.encoding=UTF-8
**(推荐)**直接使用 IDEA 控制台显示的 GBK 编码, 把 tomcat, jvm 输出的日志编码也全部改为 GBK;
toncat 安装路径下的 conf/logging.properties 配置文件中的
java.util.logging.ConsoleHandler.encoding 改成 GBK;
jvm 启动参数 VM options 加个配置 -Dfile.encoding=GBK.
如果你没有加乱七八糟的配置的话, 这个 jvm -Dfile.encoding 启动参数直接置空, 就会自动使用系统默认编码 GBK
我为什么推荐控制台使用 GBK
上面解决方式中, 第二种反而是我比较推荐的一种方式, 那有人就会问了, 全部改成 UTF-8 编码不好吗?
首先看下面的我的编码对接思想.
我的编码设置思想
第一种解决方案的弊端
第一种解决方案有什么弊端呢?
首先即便你更改了 IDEA 的控制台编码, tomcat 什么的也全部改成 UTF-8, 那么当你单独运行 tomcat 的时候, tomcat 会使用系统控制台打印日志, 那么系统控制台使用的编码是什么呢, 如果你用的是中国的 window, 那么编码格式 9 成 9 是 GBK, 因为这是你的系统默认编码, 无论是 tomcat, jvm, IDEA, 或者是其它开发软件或者是非开发软件, 编码对标的首先是你的电脑系统编码格式.
那么干脆点, 把整台电脑的编码全部改成 UTF-8 编码怎么样呢?
这绝对是个大工程量, 这不是随随便便就改的完的, 其次这会遇到很多问题, 听我一步步分析.
假如你在中国, 使用的是 window, 系统默认编码是 GBK.
首先你过去的文件, 软件使用的是 GBK 编码. 你之前写的文档, 写的笔记, 以及使用其它软件保存的文件大多都是 GBK, 改起来很麻烦.
其次网上的资源大多是 GBK, 或是一本小说, 一首歌的歌词, 或是游戏中文翻译包, 或者是视频字幕大多也都是 GBK, 这时候你碰到一个垃圾阅读器, 音乐视频播放器, 游戏软体, 它们不去识别文件 GBK 编码, 直接通过系统默认编码 UTF-8 打开, 然后就会出现乱码情况.
然后因为你的同事, 你的朋友它们电脑上大多都是 GBK 编码格式, 假如你们使用 git 或 svn 管理文档, 你使用 UTF-8 格式, 你同事大多不修改配置默认使用 GBK, 然后你觉得这样好吗? 哪怕你的编辑器能自动识别编码, 你拉娶个gbk编码文件, 改动保存后, 再以utf-8格式推送出去… 然后一个文档项目就出现了两种编码. 甚至你做个设计流程图, 建个带中文注释的数据表, 同步到你朋友的电脑上, 打开, 卧槽, 乱码了.
最后, GBK 存储汉字占用空间更小, 非开发工作没有必要使用UTF-8.
end
那么一个公司全部将电脑编码改成 UTF-8 不行吗?
可以啊, 只要你们公司要求这样就可以, 只要电脑是公司统一发放的就可以, 只要你们公司同事都愿意改系统编码就可以,
只要整个电脑全部用来做开发, 不干其它事情就可以.至于为了开发让我去更改个人电脑系统编码改成 UTF-8, 那还是算了吧, 我个人的电脑难道仅仅是为了开发吗? 我还要做其它事情呢.
而且就为了个控制台乱码更改系统编码至于吗? 第二种方式不香吗, GBK不香吗?
当然具体怎么选择, 视个人情况而定
附加技巧
如何找出具体乱码原因
想要知道你的乱码为什么乱码成那样, 请先在你的程序里面打印输出 0信1息2信息3,之后看下乱码情况是以下解码后显示的哪一种乱码, 应该就能找到你的乱码是如何乱码成你看到的样子的.
如下第6行, 原信息是0信1息2信息3, 编码格式是UTF-8编码, 但是以 GBK的方式对其进行解码后就变成了0淇�1鎭�2淇℃伅3.
上面的表格只是列举了我们绝大多数情况下涉及到的编码 US-ASCII,UTF-8,GBK,UTF-16, 可能你用了之外的其它编码,
另外上面也仅仅是展示了一层转换而已, 可能有以错误编码解码后再次被引用之后再次解码的多次错误转换的情况,
例如UTF编码的信息f以GBK的方式解码后变成了淇℃伅之后再以UTF-8的形式存储后, 再以GBK方式打开, 就变成了娣団剝浼�声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/656294
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。