CSV乱码 - UTF-8 Unicode (with BOM)

Unicode

统一码,也叫万国码、单一码(Unicode)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
如果把各种文字编码形容为各地的方言,那么Unicode就是世界各国合作开发的一种语言。
在这种语言环境下,不会再有语言的编码冲突,在同屏下,可以显示任何语言的内容,这就是Unicode的最大好处。 就是将世界上所有的文字用2个字节统一进行编码。那样,像这样统一编码,2个字节就已经足够容纳世界上所有的语言的大部分文字了。
Unicode的学名是"Universal Multiple-Octet Coded Character Set",通用多八位编码字符集,简称为UCS。
现在用的是UCS-2,即2个字节编码,而UCS-4是为了防止将来2个字节不够用才开发的。

BOM

在UCS 编码中有一个叫做 “Zero Width No-Break Space” ,中文译名作“零宽无间断间隔”的字符,它的编码是 FEFF。而 FEFF 在 UCS 中是不存在的字符,所以不应该出现在实际传输中。UCS 规范建议我们在传输字节流前,先传输字符 “Zero Width No-Break Space”。这样如果接收者收到 FEFF,就表明这个字节流是 Big-Endian 的;如果收到FFFE,就表明这个字节流是 Little- Endian 的。因此字符 “Zero Width No-Break Space” (“零宽无间断间隔”)又被称作 BOM。

UTF-8

UTF-8(8位元,Universal Character Set/Unicode Transformation Format)是针对Unicode的一种可变长度字符编码。它可以用来表示Unicode标准中的任何字符,而且其编码中的第一个字节仍与ASCII相容,使得原来处理ASCII字符的软件无须或只进行少部分修改后,便可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。

UTF-8 BOM

UTF-8 不需要 BOM 来表明字节顺序,但可以用 BOM 来表明编码方式。字符 “Zero Width No-Break Space” 的 UTF-8 编码是 EF BB BF。所以如果接收者收到以 EF BB BF 开头的字节流,就知道这是 UTF-8编码了。Windows 就是使用 BOM 来标记文本文件的编码方式的。

CSV文件乱码问题

类似WINDOWS自带的记事本等软件,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入UTF-8 BOM头。记事本等编辑器通过它来识别这个文件是否以UTF-8编码(当然即便没有UTF-8 BOM头记事本也能通过其它方式正确识别UTF-8编码)。
如果一个UTF-8编码的字符串的开头处没有BOM头又会发生什么?
举个例子

代码demo

 	/**
     * csv 写入文件头
     *
     * @param pathAndName 文件全路径名
     *                    /Users/yangcheng/Documents/dkangel.csv
     * @throws IOException IO异常,上层捕获处理
     */
    private static void addHeadToTmpCsv(String pathAndName) throws IOException {
        FileOutputStream outputStream = new FileOutputStream(pathAndName, true);
        try (OutputStreamWriter streamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
             BufferedWriter writer = new BufferedWriter(streamWriter)) {
            writer.write("姓名,年龄,性别");
            writer.newLine();
            writer.write("dkangel,25,男");
            writer.newLine();
            writer.write("张三,30,男");
            writer.flush();
        } finally {
            outputStream.close();
        }
    }
    public static void main(String[] args) {
        String path = "/Users/yangcheng/Documents/dkangel.csv";
        try {
            addHeadToTmpCsv(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

运行结果

在这里插入图片描述
可以通过Java代码生成csv文件,未指定bom标识,使用excel查看的时候中文乱码了

文件头添加bom标识

	private static void addHeadToTmpCsv(String pathAndName) throws IOException {
        FileOutputStream outputStream = new FileOutputStream(pathAndName, true);
        // 追加BOM标识
        outputStream.write(0xef);
        outputStream.write(0xbb);
        outputStream.write(0xbf);
        
        // 或者 writer.write('\uFEFF');
        ......
    }

运行结果

在这里插入图片描述

总结

Excel打开没有BOM头的csv文件时会出现乱码问题,添加bom标识后乱码问题解决

注意

bom标识只用添加一次,那就是文件头的位置。如果在数据行头部添加bom标识则单元格数据前会多一个空格出来,可以通过WPS提示看出。

附录

参考

• unicode:https://baike.baidu.com/item/%E7%BB%9F%E4%B8%80%E7%A0%81/2985798?fromtitle=Unicode&fromid=750500
• bom:https://baike.baidu.com/item/BOM/2790364
• utf-8:https://baike.baidu.com/item/UTF-8/481798

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值