Java乱码分析

前言

首先推荐下一篇讲控制台乱码的文章 https://blog.csdn.net/u011511756/article/details/107147491 老哥讲的十分具体,可以了解了解

乱码本质

大家都不想看到乱码,乱码会导致分析问题的时候,出现很多阻碍,同时对控制台输出也是一种污染.造成乱码的原因 编码方式显示和定义的编码不匹配,本质就是因为使用了错误的字符编码去解码字节流,即字节流的读取解析不一致出现了问题,每种字符编码都有自己的一套

乱码分析

正如上面所说,乱码是因为编码不匹配的问题导致的,再碰到这种情况的时候,我们的大脑一定要保持清醒,不要一看到乱码就想着去网上百度,看cvdn(雾),看知乎等等找具体的配置去解决.要知道平时我们解决bug的思路也不是这样.

确认问题->复现场景->跟踪问题->确认原因->解决问题

按照流程

  1. 问题定位

    1. 控制台
    一般 电脑系统默认编码都是 GBK, IDEA 控制台显示的编码也是 GBK.大部分都是这样,包括tomcat的
    	 控制台日志基本分为三种
     		1. 大部门是服务打印的日志,由你的框架提供,如logback,log4j,Slf4j等日志框架
     		2. 一个是tomcat提供的 tomcat localhost log(运行的一些信息,尤其是一些异常 错误 日志信息)
     		3. 一个是tomcat提供的 catalina log (访问日志信息记录的访问,时间,IP,访问的资料等相关信息)
    2. 文件转化
    一般问题都出现在文件读取上,上传的文件的编码与你解析使用的编码不一致.或者使用工具类在传递的时候默认值引起来的
    3. 网页乱码
    网页乱码的问题就比较多样化了,网页文件本身存储时使用的字符编码和网页声明的字符编码是否一致,页面本身中文的乱码,提交的表单乱码等等,还需要进一步去判断,尤其是老项目jsp html这样的.
    
  2. 对症下药

    1. 控制台

      网上的解决方案很花,十分的众多
      	idea增加启动参数: -Dconsole.encoding=UTF-8(编码不限)
      	idea和tomcat增加启动参数: -Dfile.encoding=UTF-8(编码不限)
      	修改server文件输出: 
      	<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
      	->
          <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
          增加URIEncoding="UTF-8"属性
          修改Catalina文件:
          追加:JAVA_OPTS="-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8"
          等等,但是就会出现疑问,修改了一圈下来,要是一块对了,其他不对了,结果没变,那到底是改哪里才好,这就很麻烦了
      
      1. 服务打印日志

      服务打印日志出现乱码,那问题就很明确了,你的日志框架配置的控制台输出编码跟控制台不匹配,要根据控制台去修改对应框架的编码,将两者达成一致,这里提供几个,后续的需要自己去搜索

    logback:
    	<!-- 控制台输出 -->
    	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    		<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
    			<!--格式化输出,%d:日期;%thread:线程名;%-5level:级别,从左显示5个字符宽度;%msg:日志消息;%n:换行符-->
    			<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
    			<!--修改輸出的编码-->
                <charset>GBK</charset>
    		</encoder>
    	</appender>
    log4j2:
    	<!--这个输出控制台的配置,这里输出除了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>
    
    1. tomcat日志及Catalina日志
    ## 因为基本上都是UTF-8导致的,且系统基本上默认的是GBK,所以我们要解决的不是把
    ## 其他的改成UTF-8,而是将其改回GBK,改回操作系统控制台编码,保持编码一致
    ## 操作:
    ## 打开tomcat安装目录,找到tomcat/conf/logging.properties,把里面的UTF-8,修改为GBK。
    java.util.logging.ConsoleHandler.level = FINE
    java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
    java.util.logging.ConsoleHandler.encoding = GBK
    ## 其他的保持默认,如果修改过还是还原为GBK 
    
    1. 文件转化

      这里提供一个上传文件编码字符的方法,拿到字符串后就可以去处理对应的文件了,读取对应字符编码的内容

      BufferedReader bufferedReader = new BufferedReader(new UnicodeReader(files.getInputStream(), "编码格式"));
      

      上传上来的文件格式是五花八门的,不要确定用户一定为上传正确的格式,每个电脑系统默认的txt文件默认编码还不一样嘞

          /**
           * 判断上传文件的编码字符集
           *
           * @param files
           * @return
           * @throws IOException
           */
          private String getCharset(MultipartFile files) throws IOException {
              String charset = "GBK";
              byte[] first3Bytes = new byte[3];
              try {
                  boolean checked = false;
                  BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(files.getBytes()));
      
                  bis.mark(0);
                  int read = bis.read(first3Bytes, 0, 3);
                  if (read == -1) {
                      return charset; //文件编码为 ANSI
                  } else if (first3Bytes[0] == (byte) 0xFF
                          && first3Bytes[1] == (byte) 0xFE) {
                      charset = "UTF-16LE"; //文件编码为 Unicode
                      checked = true;
                  } else if (first3Bytes[0] == (byte) 0xFE
                          && first3Bytes[1] == (byte) 0xFF) {
                      charset = "UTF-16BE"; //文件编码为 Unicode big endian
                      checked = true;
                  } else if (first3Bytes[0] == (byte) 0xEF
                          && first3Bytes[1] == (byte) 0xBB
                          && first3Bytes[2] == (byte) 0xBF) {
                      charset = "UTF-8"; //文件编码为 UTF-8
                      checked = true;
                  }
                  bis.reset();
                  if (!checked) {
                      int loc = 0;
                      while ((read = bis.read()) != -1) {
                          loc++;
                          if (read >= 0xF0) {
                              break;
                          }
                          if (0x80 <= read && read <= 0xBF) { // 单独出现BF以下的,也算是GBK
                              break;
                          }
                          if (0xC0 <= read && read <= 0xDF) {
                              read = bis.read();
                              if (0x80 <= read && read <= 0xBF) { // 双字节 (0xC0 - 0xDF)
                                  // (0x80
                                  // - 0xBF),也可能在GB编码内
                                  continue;
                              } else {
                                  break;
                              }
                          } else if (0xE0 <= read && read <= 0xEF) {// 也有可能出错,但是几率较小
                              read = bis.read();
                              if (0x80 <= read && read <= 0xBF) {
                                  read = bis.read();
                                  if (0x80 <= read && read <= 0xBF) {
                                      charset = "UTF-8";
                                      break;
                                  } else {
                                      break;
                                  }
                              } else {
                                  break;
                              }
                          } else if (first3Bytes[0] == -17 && first3Bytes[1] == -69 && first3Bytes[2] == -65) {
                              charset = "UTF-8";
                          }
                      }
                  }
                  bis.close();
              } catch (Exception e) {
                  log.error("" + e);
              }
              return charset;
          }
      
  3. 网页乱码

匿:这里不展开了,很多情况,页面的乱码不一定是页面的问题,后台输出等等,我也记不清了,理清了再追加吧

  1. 问题验证
  2. 问题解决

尾声

正如上面链接作者所说:
	IDEA, tomcat, JDK的默认配置明明已经很好了, 我们应该去适应人家, 而不是修改人家的默认配置来适应我们五花八门的log配置文件.	
对于编码我们要学会适应,而不是为了正确,走最多的路让别人适应我们,只要我们知道乱码产生的原因,那就一定能解决,路径找对就好,是个代码那问题就能
解决.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值