前言:
在编写文件读取功能的过程中,我遭遇了一个棘手的乱码难题。经过细致的排查,发现这一问题的根源在于文件的字符编码。为了帮助大家有效地克服编码差异所带来的开发挑战,因此,我收集了字符集编码的相关知识,并撰写了这篇博客,旨在帮助大家加深对字符编码的了解。
解释字符编码(概念)
人类在与计算机交互时,用的都是人类能读懂的字符,如中文字符、英文字符、日文字符等
而计算机只能识别二进制数。
毫无疑问,由人类的字符到计算机中的数字,必须经历一个过程,如下
翻译的过程必须参照一个特定的标准,该标准称之为字符编码表,该表上存放的就是字符与数字一一对应的关系。
分享一个在线编码转换平台: 汉字字符集编码查询;中文字符集编码:GB2312、BIG5、GBK、GB18030、Unicode
常用字符编码一览表:
不同字符编码的需求:
由于世界上有成千上万的语言和方言,因此需要不同的字符编码来准确地表示各种语言中的字符。
发展历史原因一览表:
字符编码:
ASCII编码(基础)
ASCII的起源和应用
ASCII编码,由美国标准协会(ASA)于1963年首次发布,是最早的字符编码标准。它能够编码英文字符和控制字符,广泛应用于各类计算机设备和通信协议中。
现代计算机起源于美国,所以最先考虑仅仅是让计算机识别英文字符,于是诞生了ASCII。ASCII可以表示128个字符,包括英文字母、数字、标点符号以及控制字符。
中文字符编码(关注)
GB2312编码:1981年5月1日实施的简体中文汉字编码国家标准。GB2312对汉字采用双字节编码,收录7445个图形字符,其中包括6763个汉字。自2017年3月23日起,该标准转化为推荐性标准:GB/T2312-1980,不再强制执行。
GBK编码:1995年12月发布的汉字编码国家标准,是对GB2312编码的扩充,对汉字采用双字节编码。GBK字符集共收录21003个汉字,包含国家标准GB13000-1中的全部中日韩汉字,和BIG5编码中的所有汉字。
GB18030编码:2000年3月17日发布的汉字编码国家标准,是对GBK编码的扩充,覆盖中文、日文、朝鲜语和中国少数民族文字,其中收录27484个汉字。GB18030字符集采用单字节、双字节和四字节三种方式对字符编码。兼容GBK和GB2312字符集。2005年11月8日,发布了修订版本:GB18030-2005,共收录汉字七万余个。2022年7月19日,发布了第二次修订版本:GB18030-2022,收录汉字总数八万余个。
BIG5编码:台湾地区繁体中文标准字符集,采用双字节编码,共收录13053个中文字,1984年实施,主要用于台湾和香港。
Unicode编码(重点)
Unicode的产生背景
Unicode应运而生,旨在创建一个全球统一的字符编码方案,使得各种语言和字符集能够在同一套编码体系下得到统一和标准化的处理。
Unicode提供了多种编码方案,如UTF-8、UTF-16和UTF-32,以适应不同的应用需求和优化存储。
Unicode的特点:
#1. 存在所有语言中的所有字符与数字的一一对应关系,即兼容万国字符
#2. 与传统的字符编码的二进制数都有对应关系,详解如下
特点2:软件是存放于硬盘的,而运行软件是要将软件加载到内存的,面对硬盘中存放的各种传统编码的软件,想让我们的计算机能够将它们全都正常运行而不出现乱码,内存中必须有一种兼容万国的编码,并且该编码需要与其他编码有相对应的映射/转换关系,这就是unicode的第二大特点产生的缘由
了解编码和解码概念:
由字符转换成内存中的unicode,以及由unicode转换成其他编码的过程,都称为编码encode
由内存中的unicode转换成字符,以及由其他编码转换成unicode的过程,都称为解码decode
编码方案(UTF-8、UTF-16、UTF-32):
Unicode 的目标?
Unicode 的主要目标是为世界上的每一个字符提供一个唯一的数字标识,称为代码点。这意味着它不仅包括从各种语言的字母和数字,还包括符号、标点、特殊字符等。这是一个非常宏大的任务,因为世界上的书写系统和符号非常多。
存储和传输的挑战!
如果我们为每一个 Unicode 字符都使用固定的字节数来存储和传输,那么对于那些只需要少量字符编码空间的文本(例如只使用 ASCII 字符的文本)来说,这将是非常浪费空间的。例如,使用 UTF-32,每个字符需要 4 个字节,这对于纯 ASCII 文本来说是非常浪费的。
相反,如果我们选择一种对所有字符都足够小的编码(例如每个字符 1 字节),那么我们将无法表示大于 256 个字符的 Unicode 范围,这显然是不够的。
为什么需要多种编码方案?
不同的编码方案试图在字符的全球性和存储/传输的效率之间找到平衡。
-
UTF-8 是变长的,它为 ASCII 字符使用 1 个字节,但可以为其他字符使用多达 4 个字节。这使得它非常适合于包含大量 ASCII 字符的文本,因为这些字符在 UTF-8 中的表示非常紧凑。
-
UTF-16 对许多常用的字符使用 2 个字节,但也可以使用 4 个字节。它对于那些常用字符大都位于基本多语言平面(BMP)的文本非常有效,如许多东亚语言。
-
UTF-32 为每个字符都使用 4 个字节,这提供了代码点到其编码的直接映射,简化了某些操作,但以空间为代价。
因此,Unicode 提供了多种编码方案,以满足不同的需求和场景。选择哪种编码方案取决于特定的应用,包括文本的性质、需要执行的操作以及存储和传输的效率要求。
# 多国字符—√—》内存(unicode格式的二进制)——√—》硬盘(utf-8格式的二进制)
看图助解:
其他亚洲字符编码(了解)
EUC-KR和EUC-JP的基本特性
这两种编码是为了在计算机系统中表示韩文和日文字符而发展的,用于支持这两种语言的特定字符集。
Shift-JIS编码的应用
Shift-JIS是一种日本字符编码,广泛用于日本的计算机系统和应用中。
扩展字符集(了解)
ISO 8859-1的介绍
ISO 8859-1,也称为Latin-1,是为表示西欧语言字符而设计的一种字符编码。它扩展了基础的ASCII字符集,包含了256个字符。
Windows-1252的特点
Windows-1252是Microsoft为西欧语言开发的一种字符编码,与ISO 8859-1非常相似,但在某些代码点上有所不同。
应用场景:
字符编码不匹配是产生乱码的一个重要原因。
- 场景 1: 跨平台文件传输后出现乱码
- 场景 2:Linux系统下中文乱码
- 场景3:网页显示乱码
- 场景 4: 文本编辑器打开文件乱码
- 场景 5: 数据库存储或查询乱码
问题解决:
博主的问题是在设计程序时未考虑读取GBK编码格式的数据从而导致的数据乱码现象。
处理思路如下:
1. 确定文件编码:
- 在大多数情况下,可能需要用户告知文件的编码,因为自动确定文本文件的编码可能是不准确的。
- 自动检测编码(例如,只需要处理UTF-8和GBK),那么可以使用一些工具库(如
uchardet
)来自动检测编码。(实际效果不一定准确!)
2. 读取文件:
- 以二进制模式打开文件以确保数据的完整性。
- 将整个文件(或一部分)读入内存。
3. 字符编码转换:
- 使用
iconv
或其他相似的库来将原始数据从其原始编码转换为目标编码(例如,从GBK转换为UTF-8)。 - 为了提高效率,可以考虑一次转换一个缓冲区而不是整个文件,特别是对于大文件。
4. 处理转换后的数据:
- 现在,可以按照普通的方式处理转换后的数据,例如按行读取、解析等。
- 如果在转换过程中遇到错误,确保有相应的错误处理机制。
5. 输出或存储数据:
- 将转换后的数据输出到屏幕、写入新文件或进行其他处理。
6. 关闭文件和清理资源:
- 关闭打开的文件。
- 清理任何使用的资源或内存。
7. 异常处理:
- 为整个过程添加适当的异常处理和错误检查,确保能够优雅地处理如文件不存在、编码转换失败等问题。
8. 测试和验证:
- 使用多种编码格式和大小的文件对您的程序进行测试,确保它可以正确并有效地处理预期的输入。
- 考虑边缘情况,如空文件、非常大的文件、包含奇怪字符的文件等。
注:具体的实现细节可能会根据实际需求和环境有所不同。
总结:
尽管如今主流开发环境(众多开发工具、库)的默认字符编码为UTF-8,这确实为我们带来了不少便利。但正因如此,我们有时会在便利性中忽视某些细节。为了避免这类问题,我们还是需要对字符编码有更为全面和深入的了解。
希望本篇内容能为您解决问题或提供有价值的参考。如果您有任何疑问或反馈,欢迎与我交流。感谢您的阅读与支持!
参考链接:9、字符编码 - 知乎