Java读写文件时的GBK和UTF8转换问题

这篇具有很好参考价值的文章主要介绍了Java读写文件时的GBK和UTF8转换问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问题引入

文件中的文本以UTF-8的编码方式存储,在Java程序中以GBK的编码方式从文件中读入,最后再将读入的内容转换为UTF-8编码,即UTF-8 --> GBK --> UTF-8。这种操作方式能正确读入文件中的内容吗?

背景知识

因为本文主要讨论不同的编码之间的转换问题,所以有必要先介绍一下文中会用到的几种编码方式。

编码和解码

将某个字符映射成计算机能存储和处理的二进制数的过程称为编码,比如字符A的ASCII编码为b0100 0001,我们通常用十六进制来表示成0x41;将某个二进制数映射成人类可读的字符的过程称为解码,编码的逆过程就是解码。

UTF-8

UTF-8编码兼容ASCII编码,也就是说任何一个ASCII编码的字符,也是UTF-8编码的字符。比如字符A的ASCII编码的十六进制表示为0x41,占1个字节,那么字符A的UTF-8编码也是0x41,占1个字节。对于一个汉字来说,需要用三个字节存储UTF-8编码,大家可以通过UTF8在线网站获得任意字符的UTF-8编码。

GBK

和UTF-8一样,GBK也是兼容ASCII编码的。对于一个汉字来说,需要用两个字节存储GBK编码,大家可以通过GBK在线网站获得任意汉字的GBK编码。

Unicode

和UTF-8一样,Unicode也是兼容ASCII编码的。对于一个汉字来说,需要用两个字节存储Unicode编码,大家可以通过Unicode在线网站获得任意汉字的Unicode编码。也可以通过GBK2Unicode在线网站获得某个GBK编码对应的Unicode编码。

实验与分析

为了回答上面的问题,我编写了两种不同的文本内容,也就是后面的实验设置1实验设置2,以此来看一下对于不同类型的文本内容,采用上述方式是否都可以正确的读取。因为Java中对文本文件的读取主要有两种类型:读入到字符串和读入到字符数组,因此我分别实现了这两种读取方式,也就是后面的实验代码1实验代码2,以此来探究不同的读取方式对实验结果是否有影响。

实验环境

  • JDK:16
  • OS:Monterey 12.2.1
  • 系统默认编码:UTF-8

实验代码1

//将文件中的内容读入到字符串
try(BufferedReader br = new BufferedReader(new FileReader(fileName, Charset.forName("GBK")))){
    String content = br.readLine();
    byte[] bytes = content.getBytes("GBK");
    String str = new String(bytes, "UTF-8");
    System.out.println(str);
}

实验代码2

//将文件中的内容读入到字符数组
try(Reader reader = new FileReader(fileName, Charset.forName("GBK"))){
    char[] content = new char[2];
    reader.read(content);
    String str = new String(content);
    byte[] bytes = str.getBytes("GBK");
    str = new String(bytes, "UTF-8");
    System.out.println(str);
}

实验设置1

文件的编码方式为UTF8,文件的内容为:

此设置下,文件中只有一个用UTF-8编码的汉字。我们知道,在UTF-8编码下,每个汉字占3个字节,大家可以自行检查一下文件的大小是否为3字节,以避免因为其它的字符(如空格等)影响复现实验的效果。

在第一个份代码中(将文件内容读入到字符串),通过单步调试可以看到,content的内容为浣�,和文件中的内容不一样,而且看起来有点像乱码。继续单步运行,将字符串按照GBK的编码方式转换为字节数组。此处需要指定编码方式为GBK的原因是,我们从文件中读取的时候指定了GBK的解码方式,因此,想要转换成字节数组也得按照GBK的方式编码。完成转换之后,得到的字节数组bytes的大小为3。现在我们已经有了GBK编码之后的字节数组bytes了,最后将其按照UFT8的方式解码成字符串,得到�?。看样子我们没能正确的读取到文本文件的内容,下面分析一下原因。

汉字的UTF8编码可以通过之前提到的在线网站得到,其为e4 bd a0,因为Java程序采用GBK的解码方式读取文件,所以当读到第一个字节e4时,判断出还需要再读一个字节才能构成完整的编码,因此现在读入的内容是e4 bd,通过在线网站知道它对应于汉字。因为Java程序内部采用Unicode编码存储字符串,所以需要将转换为Unicode编码,通过在线网站可知它对应的Unicode编码为6d 63。要注意,实际上Java程序并不需要先把GBK码解码成字符,然后再根据字符做Unicode编码,而是直接由GBK码映射到表示相同字符的Unicode码。Java程序继续读入第三个字节a0,同时判断出a0不是一个合法的GBK编码,但是此时已经读到文件的末尾了,无法继续读入下一个字节。对于此种情况,Java会将非法的GBK编码映射成默认的Unicode码ff fd,此编码对应的字符是。可以看到,这种映射具有不可逆性,我们无法从ff fd映射回非法的GBK码,也就是说,这种映射会改变我们的原始数据。分析到这儿,我们应该知道,字符串变量content在内存中的实际内容为6d 63 ff fd(不去考虑大端小端的问题),共四个字节,表示两个字符

接下来将字符串变量content按照GBK的编码方式转换成字节数组。前面说过,content的内容为浣�,首先转换第一个字符,其对应的GBK编码为e4 bd。接下来转换第二个字符,很遗憾的是,此字符并没有被GBK收录,也就是说这个字符没有对应的GBK编码,此种情况下会将其转换为GBK编码3f,它对应的字符是?。因此,字节数组bytes = [e4, bd, 3f]

最后一步将字节数组按照UTF-8的方式解码。当遇到第一个字节e4时,发现它不是一个合法的UTF-8编码,因此继续读入下一个字节,然后发现e4 bd也不是一个合法的UTF-8编码,继续读入,发现e4 bd 3f仍然不是一个合法的编码,但是已没有更多的字节可以读了。不过UTF-8解码器发现e4 bd 3f虽然不是一个合法的编码,但3f却是一个合法的UTF-8编码,它对应于字符?。此时解码器会选择将3f解码为?,而认为e4 bd是一个错误的编码,并将其解码为默认字符。因此,最终得到的解码结果为�?

以上是对运行实验代码1时的分析,也就是将文本内容读入到字符串中的情况。对于将文本内容读入到字符数组的情况,分析过程和实验代码1差不多,只是在某些地方有细微的差别。下面简要的分析一下运行实验代码2时的情况。

文件中存储的数据仍然是e4 bd a0,对e4 bd按照GBK解码得到,因为Java中的char类型也是和String类型一样,按照Unicode的编码方式存储,对应的Unicode码为6d 63,所以字符数组中的第一个字符在内存中实际存储的是6d 63。接下来对a0按照GBK解码,如前所述,a0不是一个合法的GBK码,对于此种情况,字符数组会舍弃非法的编码,因此字符数组的第二个字符仍然是默认的00 00。下一步中的将字符数组变为字符串的目的是方便转换为字节数组,经过转换之后得到的字节数组bytes = [e4, bd, 00, 00]。最后一步将字节数组按照UTF-8的解码方式转化成字符串,最终得到的解码结果为

实验设置2

文件的编码方式为UTF8,文件的内容为:

你A

首先分析代码1。文件内容你A的UTF-8编码为e4 bd a0 41,按照GBK解码得到浣燗,其对应的Unicode码为6d 63 71 d7。 因为字符串使用Unicode编码进行存储,所以content在内存中存储的内容为6d 63 71 d7。之后对content按GBK编码获得对应的字节数组,这就又回到了e4 bd a0 41,即bytes = [e4, bd, a0, 41]。最后对此字节数组按UTF-8解码得到你A

对于代码2的分析,因为e4 bda0 41都是合法的GBK编码,所以不存在丢弃数据的问题,那么代码2的分析就和代码1的分析完全相同。

结论

文件的编码方式是什么,在读取的时候就要指定什么样的编码方式。文章来源地址https://www.toymoban.com/news/detail-469995.html

到了这里,关于Java读写文件时的GBK和UTF8转换问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • dedecms编码转换方法 gbk转UTF-8,UTF-8转GBK(推荐)

    经常遇到编码转换的问题,有的是购买了模板但是模板编码与程序编码不符,导致出现乱码.今天小编给大家分享一篇教程帮助大家解决如何转换模板文件的编码和程序的编码问题,一起看看吧! 1.如何转换模板文件编码? 首先下载一个编码转换软件 51EC模板转码专用工具v1.0免费

    2024年02月03日
    浏览(34)
  • JavaScript实现字符编码转换utf-8/gbk(附完整源码)

    以上代码中,我们使用了JavaScript内置的TextEncoder和TextDecoder类来实现字符编码转换。这两个类是ES6新增的特性,需要在支持ES6的浏览器上才能正常运行。 使用示例: 运行结果说明转换成功。需要注意的是,在不同的浏览器中,对字符编码的支持程度可能不同,因此在使用时需

    2024年02月04日
    浏览(36)
  • 彻底解决Qt中文乱码以及汉字编码的问题(UTF-8/GBK)

    原文链接: 这篇文章有点长,内容有点多,如果时间急迫,可以直接翻页去末尾看结论。红色字体加粗的。 1、cpp或h文件从window上传到Ubuntu后会显示乱码, 原因是因为ubuntu环境设置默认是utf-8,Windows默认都是GBK. 我们使用的Windows系统本地字符集编码为GBK。 2、Windows环境下,Qt C

    2024年02月05日
    浏览(47)
  • Mysql导入sql文件报COLLATION ‘utf8_general_ci‘ is not valid for CHARACTER SET ‘utf8mb4‘原因

    这个错误通常是因为MySQL数据库版本较旧,不支持使用 utf8mb4 字符集,而使用了 utf8mb4 字符集的 COLLATION 排序规则。 utf8mb4 字符集支持存储更多的字符,包括一些表情符号等,而 utf8 字符集则不支持。如果MySQL版本不支持 utf8mb4 字符集,就会出现以上错误。 解决这个问题的方法

    2024年02月13日
    浏览(50)
  • 数据库编码 问题 mysql 修改字符集为utf8mb4

    数据库编码 问题 mysql 修改字符集为utf8mb4 问题 ; 当向数据库插入表,或者在表中插入数据时,出现 ERROR 1366 (HY000): Incorrect string value: ‘xBDxF0xD3xB9’ for column ‘name’ at row 1 原因 数据库编码方式 和 表编码方式 以及 插入数据(字符串)的编码方式不同 我们可以查看建表,

    2023年04月08日
    浏览(42)
  • IDEA连接TiDB报字符集不匹配问题COLLATION ‘utf8_general_ci‘ is not valid for CHARACTER SET ‘utf8mb4‘.

    最近因工作需要,部署了一套TiDB,然而通过IDEA,使用MySQL驱动连接数据库时,一直报字符集不匹配。网上找了些资料,但是并没有相关说明。最后请教了一个大佬,问题得到解决。这边记录一下,希望能帮助到遇到同样问题的人。 问题现象 IDEA连接TiDB时,成功连接,但无法

    2024年02月13日
    浏览(53)
  • 达蒙数据库:本地编码:PG_GBK, 导入文件编码:PG_UTF8错误解决

    在windows使用达梦管理工具导入.dmp文件时出现该错误 问题解决: 1、找到DM数据库的安装路径的bin 目录下 cmd 进入终端 2、输入命令行 使用dimp工具进行导入,最后需要加上FULL=Y是表示整个表格导入,但是中间可能会出现报错

    2024年02月06日
    浏览(65)
  • MySQL - 常用排序规则utf8mb4_general_ci、utf8mb4_unicode_ci、utf8mb4_bin、utf8mb4_0900_ai_ci和存储字符集 utf8 和 utf8

    在创建数据库时,我们经常会需要填写数据库名、字符集、排序规则 常用的存储字符集 utf8 和 utf8mb4 排序字符集 utf8mb4_unicode_ci 和 utf8mb4_general_ci、utf8mb4_bin、utf8mb4_0900_ai_ci 1、utf8 utf8 是 Mysql 中的一种字符集,只支持最长三个字节的 UTF-8 字符,也就是 Unicode 中的基本多文本平

    2024年02月09日
    浏览(45)
  • 执行SQL文件出现【Unknown collation “utf8mb4_0900_ai_ci”】的解决方案

    从服务器MySQL中导出数据为SQL执行脚本后,在本地执行导出的SQL脚本。 报错:Unknown collation “utf8mb4_0900_ai_ci” 打开SQL脚本,查看 utf8mb4_0900_ai_ci ,这是字段的字符集。 1、MySQL 版本不一致。 2、字符集编码不支持。 1、升级 MySQL 数据库版本 将本地5.7版本的 MySQL数据库升

    2024年02月11日
    浏览(41)
  • MySQL常用排序规则utf8mb4_general_ci、utf8mb4_unicode_ci、utf8mb4_bin、utf8mb4_0900_ai_ci和存储字符集 utf8 和 utf8mb4

    在创建数据库时,我们经常会需要填写数据库名、字符集、排序规则; 而本文主要讲述常用的存储字符集 utf8 和 utf8mb4;排序字符集 utf8mb4_unicode_ci 和 utf8mb4_general_ci、utf8mb4_bin、utf8mb4_0900_ai_ci 一般我本人创建创建数据库通常排序规则都使用utf8mb4_general_ci,因为对特殊字符的顺

    2024年01月17日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包