文章目录
- 编码与解码
- 一、字节 & 字符
- 二、编码 & 解码
- 三、字符集 & 字符编码
- 四、ASCII
- 五、ISO-8859-1
- 六、GB
- 七、Unicode
- 1、概述
- 2、发展
- 3、UTF-8 编码
- 4、UTF-16 编码
- 八、Base64 编码
- 1、概述
- 2、原理
- 3、代码示例
- 九、十六进制编码
编码与解码
一、字节 & 字符
字节 Byte
- 字节是计算机中常用的数据存储和传输单位,它是 8 位二进制数据。
- 在Java中,字节数据类型是
byte
,它占用8位(一个字节)。
字符 Character
- 字符是指人类可读的文本数据,通常是Unicode编码的一个字符。
- 在Java中,字符数据类型是
char
,它占用16位(两个字节)。
不同编码的字节占用:
- 在
ASCII
和ISO-8859-1
中,数字、英文、标点占用一个字节,不支持汉字。 - 在
GBK
中,数字、英文、标点占用一个字节;汉字占用两个字节。 - 在
UTF-8
中,数字、英文、标点占用一个字节;汉字占用三个字节。
二、编码 & 解码
计算机中的信息都是用二进制数表示的,我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。
-
编码 Encode
:按照某种规则,将 字符 存储到计算机中。 -
解码 Decode
:将存储在计算机中的 二进制数据,按照某种规则解析显示出来。
按照A规则存储,同样按照A规则解析,就能显示正确的文本符号。反之,编码和解码采用不同的编码规则,就可能导致乱码。
三、字符集 & 字符编码
不管是 编码 还是 解码,都需要参考一个规则。这个规则就是某一个编码表。
字符集 Charset
:一组字符的集合。字符编码 Character Encoding
:将 字符集 中的 每个字符 映射为 二进制数据 的规则或算法。
常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。
一套 字符集
对应着一套或多套 字符编码
,而 一套 字符编码
属于一套 字符集
。
- 可见,当指定了
字符编码
,它所对应的字符集
自然就指定了。
四、ASCII
ASCII(American Standard Code for Information Interchange)美国标准信息交换代码。
- ASCII 是一种基于 拉丁字母 的字符编码系统,用于在计算机系统中表示 文本数据 和 控制字符。
- ASCII 定义了128个字符,包括英文字母(大写和小写)、数字、标点符号和一些控制字符。
- ASCII 的 基本字符集,使用 7 位(bits)表示一个字符,共 128 字符。
- ASCII 的 扩展字符集,使用 8 位(bits)表示一个字符,共 256 字符,方便支持欧洲常用字符。
下面为ASCII码表:
ASCII 编码:把 字符A 按照 ASCII表的规则 编码成 计算机中的二进制
字符A 十进制 二进制
'A' ---> 65 ---> 0100 0001
ASCII 解码:把 计算机中的二进制 按照 ASCII表的规则 解码成 字符A
二进制 十进制 字符A
0100 0001 ---> 65 -----> 'A'
五、ISO-8859-1
ISO(International Standards Organization)国际标准化组织。
ISO-8859-1 是 ISO 发布的第一个 8 位字符集标准,包含 256 个字符,其中前 128 个字符与 ASCII 相同。
- 0-127:与 ASCII 完全相同,包含基本的英文字母、数字和控制字符。
- 128-255:包括一些常用的拉丁字母、符号和一些特殊字符,适合大多数西欧语言,如德语、法语、西班牙语等。
六、GB
由于 ASCII 字符集 不支持中文,因此,汉字编码字符集 GB(国标)应运而生。
GB2312
:前 128 个字符与 ASCII 相同,用两个字节表示汉字(包含约 7,000 个汉字和符号)GBK
:GB2312的升级版,包括了GB2312的所有内容,同时新增了近20000个新的汉字,包括繁体字和符号。GB18030
:GBK的升级版,包含了大部分的中文(简体、繁体、甲骨文、象形文等等),还有少数民族的文字,识别更多。
其中 GBK
是最常用的。
七、Unicode
1、概述
如果每个国家都定义一套自己的编码标准,结果相互之间谁也不懂谁的编码,就无法进行很好的沟通交流。
所以 ISO(国际标准化组织)定义一套编码方案来解决所有国家的编码问题,这个新的编码方案就叫做 Unicode。
Unicode字符集包含了几乎所有的已知语言的字符,包括各种字母、数字、标点符号、符号、控制字符、中文等。
2、发展
Unicode 字符集 与 ASCII 字符集 的不同之处在于,它使用了更多的位数来表示字符,以便支持更大的字符集。
- 最早的版本使用16位(两个字节)来表示字符,称为 UCS-2 编码。
- 后来随着扩展,采用了更多的位数,使用32位(四个字节)来表示字符,称为 UTF-32 编码。
- 实际应用中,为了节省存储空间,常常使用可变长度的编码方案,例如 UTF-8 和 UTF-16 编码。
3、UTF-8 编码
可变长度编码,使用1~4个字节为每个字符编码
- 1个字节:ASCII 字符(0-127)
- 2个字节:拉丁文等字符
- 3个字节:中文等字符
- 4个字节:其他极少使用的Unicode辅助字符
4、UTF-16 编码
可变长度编码,通常使用 2 或 4 个字节表示一个字符。
优点
- 对于许多常用的非英语字符(如汉字),占用的空间相对较小(通常为 2 字节)。
- 处理时,某些操作可能更高效,因为字符通常是固定长度的(2 或 4 字节)。
缺点
- 不兼容 ASCII,某些情况下可能需要额外处理。
- 对于只使用 ASCII 字符的文本,可能会占用更多空间。
八、Base64 编码
1、概述
Base64 编码 是一种将 二进制数据
转换为 ASCII字符串
的编码方式(编码后的一组字符只包含 ASCII 可打印字符)
- 通常用于在网络传输中以文本形式传输二进制数据,或者用于在文本协议中嵌入二进制数据。
- 通常是由64个字符组成,包括26个大写字母、26个小写字母、10个数字以及一些特殊字符(+、/、= 等)
2、原理
- 输入:Base64 编码的输入是二进制数据,例如 文件内容 或 图像。
- 分组:将输入的二进制数据每 3 个字节(24 位)作为一组进行处理。
- 拆分:将 24 位的数据拆分为 4 个 6 位的部分。
- 映射:根据这 6 位的值在 Base64字符表 中查找对应的字符。
- 填充:如果输入的字节数不是 3 的倍数,会在输出末尾添加一个或两个
=
字符作为填充。
Base64 字符表如下(对应 6 位二进制)
ABCDEFGHIJKLMNOPQRSTUVWXYZ (0-25)
abcdefghijklmnopqrstuvwxyz (26-51)
0123456789 (52-61)
+ (62)
/ (63)
3、代码示例
import java.util.Base64;
public class Base64Example {
public static void main(String[] args) {
String originalString = "Hello, Base64!";
String encodedString = Base64.getEncoder().encodeToString(originalString.getBytes());
String decodedString = new String(Base64.getDecoder().decode(encodedString));
System.out.println("Original: " + originalString);
System.out.println("Encoded: " + encodedString);
System.out.println("Decoded: " + decodedString);
}
}
九、十六进制编码
Base64编码、AES加密的密文会经常出现/
, 跟url里分隔用的/
相同,可能会引起一些其它问题。
使用十六进制编码,密文只会存在数字和字母。
public class HexExample {
public static void main(String[] args) {
String originalString = "Hello, Hex!";
String hexString = toHex(originalString.getBytes());
byte[] bytes = fromHex(hexString);
System.out.println("Original: " + originalString);
System.out.println("Hex: " + hexString);
System.out.println("Decoded: " + new String(bytes));
}
public static String toHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
public static byte[] fromHex(String hex) {
int len = hex.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
+ Character.digit(hex.charAt(i + 1), 16));
}
return data;
}
}