IDEA中控制台启动乱码(淇℃伅)的原因简单分析

0、文章内容说明

我们在使用IDEA的时候,项目通常会配置自己的tomcat,但是有时你会发现项目启动的时候控制台会报错,虽然说这个不会影响项目的运行,但是作为有强迫症的人来说,还是很难忍受这个乱码的。今天我们就来对这个现象做一个简单的探究。以下结果和现象都是本人在使用过程中出现的,每个人的情况可能都不同,需要能对大家有所帮助。

图1.tomcat启动时的报错

图1. tomcat启动时的乱码

图2.中文乱码
图2. 日志中文乱码

图3.文件路径乱码
图3. 文件路径中文乱码

1、以utf8编码,gbk解码的乱码

如果是以utf8编码,gbk解码时,就会出现乱码的现象。因为中文在utf8编码中,是占三个四个字节 (其中四个字节的不常见,主要以,平时一般都用不到。但实际情况却是四个字节的汉字总数比三个字节的汉字总数还多,U+20000 - U+2FA1D : 0xF0 0xA0 0×80 0×80 - 0xF0 0xAF 0xA8 0x9D,共 64029 个为不常见汉字,这里暂时不考虑)

而gbk编码中,中文是占两个字节,gbk会以两个字节进行解析。举个例子,假入有两个字以utf8编码时,共有六个字节(这里默认为一个汉字占用三个字节),而以gbk解码时,就会解析出三个字。以上面的图1为例。

但是,但是,如果是单个中文字符的话,大多数情况下以utf8编码都是三个字节,gbk解码时,把第一个和第二个字节一起解码,此时还剩一个字节,因为gbk没有单字节的字符,所以会把这个字节变成3f,不管原来这个字节是什么。而3f用utf8解码出来是?,所以这种情况即使再用gbk编码,utf8解码都不能回到原样了。

所以,综上总结,如果中文字符数是偶数,utf8编码后也是偶数( 偶数×3=偶数),如果出现了伅℃淇等之类的乱码,即没有问号?字符。我们应该要想到,这应该是utf8编码,然后用gbk解码造成的,所以可以再用gbk编码,utf8解码还原回去。但是,如果中文字符是单数,( 单数×3=单数 ),这就意味着最后一个字节,不论是什么,都会被转化成3f,此时原始的二进制最后一个字节已经被破坏了(除去本身为3f的情况),此时,无论用什么编码和解码方式,最后的那点数据一定是丢失的。

额外说明下:既然按两个字节或三个字节编解码可能会产生问题,那我们能不能按单个字节来编解码呢,这样的话,无论是什么,我们都能保证原始数据不被破坏,就是显示的时候会有问题,比如乱码之类的,但是这种只是显示的乱码我们可以在后期中还原,因为原始数据没有被破坏。还真有,iso-8859-1就是,大家可以自行来尝试以下。


补充知识

在Java中,是以utf-16格式作为内存的字符存储格式,但是在编码的过程中,我们可以指定为utf-8、gbk或其它编码格式,最后存储的时候都会转化为utf-16格式。中文大多是占用两个字节(注意和utf8区分,utf8中,大部分常见中文都是三个字节),只有极少部分中文要用四个字节来表示(这个暂时先不讨论这种情况)

无论是utf8转gbk,还是gbk转utf8等,都不是直接转化的,是先转为Unicode格式(特指utf-16),然后再转化为另一种格式的。

/**
 * @description: 简单探究tomcat乱码的小原因。
 * @author: zhong
 * @date: 2020/11/3 9:22
 * @motto: talk is cheap, show me your code!
 */
public static void main(String[] args) {

        System.out.println(Charset.defaultCharset().name());


        List<String> strs = new ArrayList<>(10);
        strs.add("信息");
        strs.add("**淇℃伅**");
        strs.add("用户登录主页");
        strs.add("鐢ㄦ埛鐧诲綍涓婚〉");
        strs.add("你");
        strs.add("��");
        strs.add("你好呀");
        strs.add("浣犲ソ鍛�");

        encodeAndDecode(strs);

    }

    public static void encodeAndDecode(List<String> strs) {
        int count = 0;
        boolean flag = false;
        for (String s : strs) {

            flag = ((count++) % 2 == 0) ? true : false;

            if (flag) {
                System.out.println("正常:" + s);
            } else {
                System.out.println("乱码:" + s);
            }

            try {

                //utf8编码,gbk解码
                byte[] utf8Bytes = s.getBytes("utf8");
                System.out.print("utf8 encode(utf8编码):");
                for (byte b : utf8Bytes) {
                    System.out.print(Integer.toHexString(b & 0xff) + ",");
                }
                System.out.println();
                String utf8ToGbk = new String(utf8Bytes, "gbk");
                System.out.println("utf8 encode, gbk decode(utf8编码,gbk解码):" + utf8ToGbk);

                //gbk编码,utf8解码
                byte[] gbkBytes = s.getBytes("gbk");
                System.out.print("gbk encode(gbk编码):");
                for (byte b : gbkBytes) {
                    System.out.print(Integer.toHexString(b & 0xff) + ",");
                }
                System.out.println();
                String gbkToUtf8 = new String(gbkBytes, "utf8");
                System.out.println("gbk encode, utf8 decode(gbk编码,utf8解码): " + gbkToUtf8);


                if (!flag) {
                    System.out.println("-----------------------------------------------");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

结果如下:
图4

图4. 双数字节可恢复乱码的例子

由图4图片,易得出结论:根据代码结果可知,偶数的汉字,utf8编码正常情况下都是偶数。如果中文显示出现了一些莫名奇妙的中文,而且其中没有问号?,那么,大概率是utf8编码的格式,以gbk解码造成的。此时,原始数据还没有破坏,我们只需要再将这些字以gbk编码,utf8解码即可


中文“你”、“你好呀”等因为为单数,所以utf8编码时产生的总字节数也为单数,后期gbk解码时,最后一个字节会变成3f,发生了乱码。后面再重新用gbk编码,utf8解码,最后那部分还是会乱码。
图5

图5. 单数字节不可恢复的情况

由以上结果可知,utf8编码格式的时候,“信息”对应的格式应该是有六个字节,以gbk解码的话,就会出现个字,
查阅其gbk编码得知:

淇:E4 BF
图6

图6. 淇的gbk编码

℃:A1 E6图7

图7. ℃的gbk编码

伅:81 AF
图8

图8. 伅的gbk编码

根据utf8的编码格式(不太清楚的自己去网上复习下,然后再看接下来的内容),这应该是两个字符,分别为E4 BF A1、E6 81 AF,查阅utf8编码表,得知为:

:E4 BF A1
(补充说明:以图片中第一个“俘”字为例,B7FD为gbk格式,4FD8为utf16格式,E4 BF 98为utf8格式,以下类同):
图9
:E6 81 AF
图10结论:以utf8编码,用gbk解码时,会以两个字节两个字节的解码,所以会造成中文乱码,但是,此时编码格式还没有乱(中文字符为奇数时,会有乱码,还原不回去,前面已经说过),只需将“淇℃伅”用gbk编码,utf8再解码一次即可。如果项目中出现这样的乱码,要注意是不是哪里用了utf8编码,然后用gbk解码导致的。

2、以gbk编码,utf8解码的乱码

继续以上面这张有代码的图为例,代码还是不变,以gbk编码,然后utf8解码时,遇到无法解析字符时,就会以?代替,此时原有的编码已经破坏了,后面即使再用utf8编码,用gbk解码也是会出现乱码的情况,这个就不做讨论了。总结:以gbk编码,utf8解码的话,原有的编码已经被破坏,这时已经是无法还原的了。具体可以看下下面的参考文章

更详细的参考文章:

https://blog.csdn.net/csdn_ds/article/details/79077483

3、解决IDEA中tomcat启动时出现的(淇℃伅)的解决办法

  • 个人认为出现该现象的可能原因:IDEA内部是用utf编码的,但是控制台显式的时候是用gbk解码的,这时我们再用gbk编码回去,用utf8解码就能正常了。即在下面第二条中修改编码为GBK。
    • :如果乱码中没有问号?之类的符号,一般情况下原来的编码都没有破坏,只不过是一样的编码,用不同的方式解码造成的结果。
    • 暂时还留有的疑问:如果IDEA中所有的编码都设置为了utf(这里指utf8),为啥在控制台显式的时候会以gbk来解码,难道会转化为操作系统的默认语言的?以gbk编码回去,它能显示正常,说明最终控制台还是以utf8解码的。以下为个人猜想,还未经过验证,如果有知道的大佬,希望能指点一下这个地方
      • 修改配置前:IDEA(utf8编码)---->tomcat(gbk解,utf8编)---->IDEA控制台(utf8解)
      • 修改配置后:IDEA(utf8编码)---->tomcat(gbk解,gbk编)---->IDEA控制台(utf8解)
  1. 首先修改IDEA中所有的地方为utf8编码
    参考文章:

https://blog.csdn.net/m0_38132361/article/details/80628203

  1. 在tomcat的conf/loggin.properties文件中追加(具体可以参考网上其它教程)
    java.util.logging.ConsoleHandler.encoding = GBK

如果原来的是
java.util.logging.ConsoleHandler.encoding = UTF-8
则改为:
java.util.logging.ConsoleHandler.encoding = GBK


补充说明的参考文献

  1. utf8编码中,汉字到底占用几个字节。汉字占用3-4个字节,通常情况下可认为是3个字节

    https://blog.css8.cn/post/11228387.html

大神级别的乱码理解 强烈推荐!!!

https://blog.csdn.net/u011511756/article/details/107147491

  • 10
    点赞
  • 13
    收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 8

打赏作者

zhm_cs

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值