java “错误:编码GBK 的不可映射字符”

  • Post author:
  • Post category:java



目录


前言


一、透过现象看本质,发现问题找原因


1.查看cmd的默认编码格式:


2.查看代码文件的保存格式:


二、分析问题原因,寻找解决方案


1.指定DOS命令的编码格式:


2.修改代码文件的编码格式:


三、后续——踩坑~


问题来了~为什么通过记事本将ANSI编码格式转换为UTF-8编码格式后,出现错误: 非法字符: ‘\ufeff’


填坑~解决方案:



前言

小编最近在写javaDemo时,使用的是文本文档,后缀名为.java的形式,代码中因为有中文以及特殊符号存在,导致DOS编码后出现错误:“编码GBK 的不可映射字符”。

javaDemo代码:

/*
 * 运算符之一:算术运算符
 *  + - * / % (前)++ (后)++ (前)-- (后)--  +(连接符)
 */
class Test {
    public static void main(String[] args) {
        //除号:/
        int num1=12;
        int num2=5;
        int result=num1/num2;
        System.out.println(result); // 2

        int result2=num1/num2*num2;
        System.out.println(result2); //10

        double result3=num1/num2; //int转double
        System.out.println(result3); //2.0

        double result4=num1/num2+0.0; //2.0: int转double

        double result5=num1/(num2+0.0); //2.4 : 12/5.0=2.4
        System.out.println(result5);

        double result6=(double)num1 / num2; //2.4:double12/int5=2.4
        System.out.println(result6);

        double result7=(double)(num1/num2); //2.0:int2转为double
        System.out.println(result7);


    }
}

使用javac命令编译,出现的问题:

一、透过现象看本质,发现问题找原因

既然问题描述显示为 java “错误:编码GBK 的不可映射字符”,那便确定应该是编码格式的原因。进一步思考,为什么会出现编码格式的问题呢?——查看cmd默认的编码格式与文件的编码格式是否一致?

1.查看cmd的默认编码格式:

  • 通过cmd命令查看:chcp

  • 通过属性查看:

通过两种方式查看cmd的默认编码格式都是936,936是什么呢?


CP936其实就是GBK,IBM在发明Code Page的时候将GBK放在第936页,所以叫CP936。

2.查看代码文件的保存格式:

通过记事本,打开代码文件:


查看代码文件的格式,发现文件的编码格式默认是UTF-8,与cmd的默认编码格式不同。

关于GBK和UTF-8编码格式的区别:

GBK全称《汉字内码扩展规范》(GBK即“国标”、“扩展”汉语拼音的第一个字母,英文名称:Chinese Internal Code Specification) ,中华人民共和国全国信息技术标准化技术委员会1995年12月1日制订,国家技术监督局标准化司、电子工业部科技与质量监督司1995年12月15日联合以技监标函1995 229号文件的形式,将它确定为技术规范指导性文件。这一版的GBK规范为1.0版。

而UTF-8: UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码。由Ken Thompson于1992年创建。现在已经标准化为RFC 3629。UTF-8用1到6个字节编码UNICODE字符。用在网页上可以同一页面显示中文简体繁体及其它语言(如英文,日文,韩文)。


所以GBK和UTF-8简单的来说,

区别就是编码方式不同,表示的文字范围不同。

二、分析问题原因,寻找解决方案

既然发现cmd默认的编码格式与文件的编码格式不一致,那便解决编码不一致的问题,可以从两方面入手:

1.指定DOS命令的编码格式:


根据代码文件的格式(UTF-8),指定DOS命令的编码格式为UTF-8:javac -encoding UTF-8 Test.java

编码通过:

2.修改代码文件的编码格式:


根据cmd的默认编码格式,记事本打开java源文件,另存为文件编码格式选择ANSI(

埋雷、踩坑!!!

):

再使用cmd默认的编码格式执行javac命令,编译成功:

说明:

ANSI:美国国家标准协会,系统预设的标准文字储存格式。简体中文编码GB2312,实际上它是ANSI的一个代码页936

UTF-8:通用字集转换格式,这是为传输而设计的编码,2进制,以8位为单元对Unicode进行编码,如果使用只能在同类位元组内支持8个位元的重要资料一类的旧式传输媒体,可选择UTF-8格式。

在UTF-8里,英文字符仍然跟ASCII编码一样,因此原先的函数库可以继续使用。而中文的编码范围是在0080-07FF之间,因此是2个字节表示(但这两个字节和GB编码的两个字节是不同的),用专门的Unicode处理类可以对UTF编码进行处理。

通过以上两种方式将javac执行命令的编码格式与文件编码格式统一,这样便可以成功编译!

三、后续——踩坑~

虽然通过

记事本打开java源文件,另存为文件编码格式选择ANSI,这种方式可以实现javac成功编译代码文件,但是会导致代码中的中文和特殊字符显示为乱码,如下图所示;


既然如此,那小编想把ANSI编码格式的文件重新另存为UTF-8,然后采取指定DOS为UTF-8的方式解决编码问题,结果出现了新的问题:


指定DOS命令的编码格式为UTF-8:javac -encoding UTF-8 Test.java,出现新的问题:

Test.java:1: 错误: 非法字符: ‘\ufeff’

问题来了~为什么通过记事本将ANSI编码格式转换为UTF-8编码格式后,出现


错误: 非法字符: ‘\ufeff’



寻找原因:通过不同的代码工具打开该文件,查看该文件的编码格式是否成功转换为UTF-8格式:

①通过Windows记事本打开,显示为UTF-8:

②通过IDEA打开该文件,显示为UTF-8:



③通


过Visual Studio Code 打开,发现该文件并没有转换成了UTF-8格式,而是UTF-8 with BOM格式:

为什么使用不同的编译器查看到的该文件编码格式不一致呢?

原来这是因为Windows记事本在修改UTF-8文件时自作聪明地在文件开头添加BOM导致的,而IDEA没有智能的把UTF-8+BOM文件转为普通的UTF-8文件的功能,所以在IDEA中显示的是UTF-8,但是IDEA却不能正确读取.java文件,从而程序出错。

而在VSCode中可以看到通过记事本将ANSI编码格式转换为UTF-8编码格式后,实际是转换为UTF-8 with BOM,这也证明了

通过记事本转换编码格式是存在问题的!!!

填坑~解决方案:

1.在编辑器IDEA中将文件编码更改为UTF-16,再改回UTF-8即可,其实就相当于刷新了一下文件编码。

2.直接通过VSCode或者其他可以区分UTF-8和UTF-8 with BOM的编译器(如EditPlus、Notepad++)修改文件编码格式为UTF-8,避免使用记事本(记事本存在编码转换问题!!!)。



版权声明:本文为Ginny97原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。