前言
在编程语言中, 我们常常会接触到一些二进制数据, 例如 Python 中的 Bytes 类型数据, Nodejs 中的 Buffer 类型数据. 如果不能理解二进制数据和 unicode 数据的关系, 以及字符编码的作用, 那么在面对一些需要进行编码/解码的需求时, 就会毫无思路.
由于 Python2, 3 的版本差异, 字符编码是一个绕不开的知识点.
在下文中, 我会将编程语言中的二进制数据和现实生活中的事物进行类比, 以达到帮助理解效果.
Python Bytes 二进制数据和 unicode 数据 - 正如罐头和食物的关系
Python 中的 Bytes 字节类型是存储在硬盘上的二进制数据, 是由 unicode 数据经过编码得来, 用于存储和传输. ( 正如食物需要密封后才能保存和传输 )
unicode 数据, 是计算机内存中统一使用的数据类型, 是内存中运行的程序能够 "理解" 的数据, 由 二进制 数据解码而来. ( 正如密封的食物需要解封才能食用 )
二进制数据 数据和 unicode 数据之间, 存在着编码和解码的对应关系. 在传输和写入数据到硬盘时, 都需要进行编码的操作. 在读取数据时, 需要进行解码的操作.
字符编码就是字典
常见的 ASCII, UTF-8, GBK 都是在unicode数据和二进制数据的转换过程中所使用的编码.
默认地, 在读写文件时, 程序会根据当前计算机系统使用的字符编码来确定编码解码时使用的"字典".
解码:
在读取硬盘文件的时候, 软件根据当前环境使用的字符集 ("字典")将硬盘上的二进制数据解码 ("翻译") 为unicode数据.
编码:
在存储数据到硬盘上的时候, 软件会根据字符集将unicode数据编码为二进制数据.
在网络传输数据的时候, 传递的也都是二进制数据.
使用一致的字符编码是必要的
使用不一致的字符编码就好比是我们 "拿着英汉词典来翻译西班牙语文章" .
为此我们会通过 shebang 指示解释器去使用特定的字符编码.
-*- coding: utf-8 -*-
或者是在HTTP的响应中指示浏览器数据使用的字符集
网络运输时的序列化和反序列化 - 食物的密封和拆封
序列化
序列化是将内存中的数据 (unicode数据) 变成可存储传输数据(二进制数据) 的过程.
在通过网络传输数据的时候, 我们需要首先将数据进行序列化处理.
反序列化:
获取到响应数据时, 需要对数据进行反序列化处理.
字符编码的应用场景:
了解了序列化和反序列化之后, 我们就可以很容易地理解那些需要转换数据类型的场景:
- Python server socket 和 client socket 之间的数据交互:
socket.send() 只能发送bytes数据 - 前端使用 Ajax 和服务器交互时需要序列化数据.
- 向文件写入数据, 读取文件时都需要指定编码格式.