Java 字符集配置及 ObjectMapper 映射 utf8 bom 文件时的错误分析

1. Java 读取文件时的字符集配置

utf-8 文本文件 test.txt

{
	"name": "shanghai",
	"label": "\"上海\""
}

1.1 默认字符集

比如在 Windows 平台,打开 CMD,可以查看本地字符集:
在这里插入图片描述

public static void main( String[] args )
    {
        try ( FileReader r = new FileReader("test.txt")){
            System.out.println(r.getEncoding()); // 查看 Java 解析文本所用的字符集
            char[] buf = new char[100];
            r.read(buf);
            System.out.print(buf);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

编译程序,生成 demo.jar,执行:

java -jar demo.jar

打印出来的结果为 GBK! 文本解析出现乱码,因为文件编码是 utf-8。

1.2 配置 Java 字符集

可以肯定的是,Java 程序并不会去识别文件本身到底是什么格式,而是根据配置的字符集去解析文本文件。

默认情况下,会读取系统本地的字符集配置,当然也可以自定义。

方法 1、 通过命令行参数配置: -Dfile.encoding

java -jar -Dfile.encoding=UTF-8 demo.jar

文件的解析编码为 UTF8,内容解析正确!

方法 2、通过编码进行配置:
当通过命令行配置时,会影响整个程序解析文本的方式,有时候,想对特定文件指定特定的解码方式,就需要在代码中进行设定了!

Java 中 InputStreamReader 负责将从文件中读取的字节流转换为字符流,可以指定字符集。
在这里插入图片描述

代码如下:

String encoding = new InputStreamReader(new FileInputStream("test.txt"), "utf-8").getEncoding()
System.out.println(encoding); // utf-8

1.3 IDEA 调试程序时的陷阱

IDEA 调试程序时,会添加很多参数,包括字符集配置。

可以通过 Jconsole 查看 IDEA 启动的 Java 程序的 VM 参数,如下:
在这里插入图片描述

因此,在读取外部文件时,如果该文件是 utf-8 格式,那么通过 IDEA 调试时,读取并解析文件是没有问题的,但当通过 java 命令执行程序时,如果没有指定 -Dfile.encoding 参数,且本地字符集配置的是 GBK,就会出现错误(乱码),而这种错误显得很诡异,因为在测试环境上有问题,本地调试却无法复现!!!!

2. utf-8 与 utf-8 No Bom

首先,UTF-8 不需要 BOM,尽管 Unicode 标准允许在 UTF-8 中使用 BOM。不含 BOM 的 UTF-8 才是标准形式,在 UTF-8 文件中放置 BOM 主要是微软的习惯。

在 Windows 平台,用记事本打开并保存的文件,默认就是 utf-8 bom 文件,bom 文件会在文件头上添加 EF BB BF 字节流。

使用 ultra edit 查看 test.txt 的十六进制内容:
utf-8 no bom
在这里插入图片描述

utf-8 bom
在这里插入图片描述

使用 ultra edit 可以将文件另存为期望的格式:
在这里插入图片描述

此外, IntellJ IDEA 创建和保存的文本文件是 no bom 的,毕竟 Java 是平台无关的!!!

3. ObjectMapper 与 bom

编程语言一般都是平台无关的,因此 bom 文件常常会诱发一些错误!

Java 本身就是平台无关的,所以当 Java 在读取 utf-8 bom 文件时并不会自动忽略掉 Windows 为文件添加的 EF BB BF 文件头,而是将 EF BB BF 视作文件内容。

因此当使用 ObjectMapper 将文件中的 json 字符串转换为 Object 时,utf-8 bom 文件会报错!

com.fasterxml.jackson.core.JsonParseException: Unexpected character ('' (code 65279 / 0xfeff)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')

这时,需要将文件转存为 no bom 格式!

测试代码

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.FileReader;

public class Demo
{	
	public static class Data {
        String name;
        String label;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getLabel() {
            return label;
        }

        public void setLabel(String label) {
            this.label = label;
        }

        @Override
        public String toString() {
            return "Data{" +
                    "name='" + name + '\'' +
                    ", label='" + label + '\'' +
                    '}';
        }
    }

	public static void main(String[] args)
	{
		try ( FileReader r1 = new FileReader("test.txt");
			  FileReader r2 = new FileReader("test.txt")){

            Data d = new ObjectMapper().readValue(r1, Data.class);
            System.out.println(d);

            System.out.println(r2.getEncoding());
            char[] buf = new char[100];
            r2.read(buf);
            System.out.print(buf);
        } catch (Exception e){
            e.printStackTrace();
        }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值