先说结论:
java -jar运行时的编码方式和该下载文件的编码方式不一致导致的
1. 场景/问题
客户端 下载excel文件时,下载下来的文件中文乱码,且表头和数据也是错位的
2. 排查
肯定是文件编码类型冲突导致的。
-
项目运行所在电脑是window,默认的系统编码是GBK。程序运行(java -jar)时并没有指定JVM输出字符串的编码格式,所以就是GBK。
-
项目中文件下载的代码
可以发现,在写文件的过程中,指定了被写入的文件的编码格式是UTF8. -
所以,项目运行后,当前端执行下载命令时,触发该条语句就会创建一个UTF编码格式的文件,但是整个程序是以GBK编码格式输出字符串的,整个文件返回也是要遵从GBK编/解码。所以相当于用GBK去解码UTF8编码的文件,当然就会发生中文乱码异常
3. 解决
既然你创建文件是UTF8,那不如指定运行时的JVM输出编码也是UTF-8
java -jar -Dfile.encoding=UTF8 ROOT.war
但是
这时候发现控制台输出日志和日志文件中的日志又是中文乱码了。
因为window的cmd默认编码格式是GBK,你输出的字符串编码是UTF8,当然控制台显示的时候就会乱码了。
解决方法:
修改cmd的编码格式 :chcp 65001
-Dfile.encoding=UTF-8
从file,可以推断和文件有关。
使用java.io中的方法时,会使用file.encoding取得具体的编码方式。
所以。-Dfile.encoding就是为了改变jdk处理文件【程序中使用OutPutStreamWriter】的默认字符编码,
如果不手动设定,默认的file.encoding是当前操作系统的默认编码,也就是GBK
chcp
chcp
cmd中,chcp返回是当前操作系统的默认编码格式的号码
963对应GBK(window默认的)
65001对应UTF-8
MORE
1. window记事本的默认编码格式
修改记事本的编码格式
window中记事本默认的编码格式是UTF-8
另存为修改编码格式
2. cmd的type命令
type
类似于linux的cat
,将一个文件转到屏幕
一、编译过程
测试代码:hello.java
1. 控制台打开文件
public class Hello {
public static void main(String[] args) {
System.out.println(System.getProperty("file.encoding"));
System.out.println("你好,中国");
}
}
window上,用sublime text保存文件
- save with encoding utf-8
输出乱码,hello.java
【UTF8】 和 cmd【GBK】冲突。这是因为window的cmd默认编码是GBK,你以UTF-8编码格式保存的文件,用GBK解码UTF编码的文件肯定会出现异常的
(控制台展示文件,也可以看成是对源文件的一个解码过程) - save with encoding GBK
2. 编译源文件
编译,肯定要先读再编译啊,关键是【不能正确的读】是乱码的一个原因
导致乱码的不是Java源码编译器的“编码”(以UTF-8保存的、)的过程,而是“解码”(读入.java源码内容)的过程
例:
-
BK保存的文件:
成功编译 -
UTF保存的文件:
对于javaCompiler,如果在不指定源文件编码类型的情况下,将会用系统默认编码去解码源文件。
这里,就相当于,用javaCompiler用GBK去解码UTF编码的源文件了,当然会产生乱码。
-encoding UTF8
所以,需要指定源文件的编码类型,这里用-encoding UTF8
指定。这样javaCompiler才知道用什么解码类型去解码源文件
二、执行过程
也就是执行class文件的过程
class文件的编码格式都是固定的,UTF8。javaCompiler解码.java后会编译成UTF8格式的class文件
1. 执行文件
GBK源文件:
为啥这两个都是正常的呢?
2. 乱码
一直编译正确的情况下,为什么运行的时候还会产生中文乱码?
那原因肯定是在JVM 从.class文件读取这个字符串字节流并构建String对象的时候采用了错误的字符编码来构建字节流。
进而导致从JVM输出字符串的字节流到我们控制台的时候,出现乱码
所以,如果确定是运行时的乱码,那就是控制台的问题了。默认是用控制台的编码方式输出字符串的。
(1)改变控制台运行环境
(2)决定这个文件,以何种方式输出字符串。-Dfile.encoding
三、idea中的编码配置
1. 控制台乱码
源码: 右下角有这个文件的编码格式,UTF8
发现输出GBK,且中文乱码了。这已经是运行时的结果了。
查看class文件,发现在编译后的class文件中就已经乱码了,是编译时的乱码。
class文件,这时候发现右下角是GBK,应该是java compile解码类型
所以,问题就出在javaCompile解码的方式不对了,全局设置编译器的解码方式,实际
注意,修改之后,需要重启idea才能生效
这时候可以再去运行,可以看到
class文件中是正常的中文
2. maven打包编译编码
如果是maven打包文件,有
<properties>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties>
<build>
<finalName>ROOT</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>