很多人说,编码与解码太迷了,根本不知道它是在编码什么,在解码什么。或许这时,你应该尝试一下我这篇文章。
从源头来说,还是因为计算机和人的根本区别,计算机看的是二进制机器码,而我们只能看懂特殊字符(英文,中文),把特殊字符变成二进制码的过程就成为
编码
。又由于地球上存在很多种类的语言,每种语言的每个元素都是一个字符(例如中文“你”,“好”),把中文字符变成二进制机器码,这个过程就称为
有一定格式的编码
,或者叫
编码方式
。
- 编码: 把看得懂的字符变成看不懂码值这个过程我们称作为编码。
- 解码: 把码值查找对应的字符,我们把这个过程称作为解码。
- 注意: 以后编码与解码一般我们都使用统一的码表(码表,即编码方式)。否则非常容易出乱码。
码表
欧美地区常用编码:
- ASCII:美国标准信息交换码。用一个字节表示。
- ISO8859-1:拉丁码表。欧洲码表,用一个字节的8位表示。又称Latin-1(拉丁编码)或“西欧语言”。ASCII码是包含的仅仅是英文字母,并且没有完全占满256个编码位置,所以它以ASCII为基础,在空置的0xA0-0xFF的范围内,加入192个字母及符号,以供使用变音符号的拉丁字母语言使用。从而支持德文,法文等。因而它依然是一个单字节编码,只是比ASCII更全面。
中文简体编码:
- GB2312:英文占一个字节, 中文占两个字节。中国的中文编码表。
- GBK:中国的中文编码表升级,融合了更多的中文文字符号。
中文繁体编码:
- Big 5:每个字使用 2 bytes
国际上通用的编码:
- Unicode:又称宽字节编码,国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode。
- UTF-8:自动区分中英文,英文占一个字节,中文占三个字节。
- UTF-16: 不管英文中文都是占两个字节。
Java编码
编码功能:字符串 --> 字节数组
- String类的getBytes() 方法进行编码,将字符串,转为对映的二进制,并且这个方法可以指定编码表。如果没有指定码表,该方法会使用操作系统默认码表。
- 注意:中国大陆的Windows系统上默认的编码一般为GBK。在Java程序中可以使用System.getProperty(“file.encoding”)方式得到当前的默认编码。
//编码用字节数组;解码用String类;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws UnsupportedEncodingException {
String value = System.getProperty("file.encoding");
System.out.println("系统默认的编码为 " + value);
String str = "中国";
byte[] buf = str.getBytes("utf-8");// 平台默认的编码表是gbk编码表,这里指定使用utf-8
System.out.println("数组的元素:"+Arrays.toString(buf)); //输出各个元素的编码码号
str = new String(buf,"utf-8"); //什么编码方式,就用什么解码方式
System.out.println("utf-8解码后的字符串:"+ str); //编码与解码一般我们都使用统一的码表才不会出现乱码;
str = new String(buf,"unicode");
System.out.println("unicode解码:"+ str); //使用unicode去解码,输出乱码;
}
}
/* 输出:
系统默认的编码为 GBK
数组的元素:[-28, -72, -83, -27, -101, -67]
utf-8解码后的字符串:中国
unicode解码:?鮽
*/
Java解码
解码功能:字节数组 --> 字符串
- String类的构造函数完成。
- String(byte[] bytes) 使用系统默认码表
- String(byte[],charset) 指定码表
- 注意:我们使用什么字符集(码表)进行编码,就应该使用什么字符集进行解码,否则很有可能出现乱码(兼容字符集不会)。
存文件时可以使用各种编码,但是解码的时候要对应的采用相同的解码方式。我们的字符流自动的做了编码和解码的工作,写一个中文,字符流进行了编码,存到了计算机中读到了一个字符,字符流进行了解码,我们可以看到字符。因为文件存的都是二进制。但是拷贝图片时,是纯二进制,不是有意义的字符,所以码表无法转换。
编码兼容
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws UnsupportedEncodingException {
String str = "a中国";
byte[] buf = str.getBytes("unicode"); //编码与解码的时候指定 的码表是unicode实际上就是用了utf-16.
System.out.println("数组的内容:"+ Arrays.toString(buf));// -2, -1, 0, 97, 78, 45, 86, -3 :unicode编码使得开头有“-2,-1”,直接忽略其即可;
str = new String(buf,"unicode");
System.out.println("Unicode解码:"+str); //正常显示;
str = new String(buf,"utf-8");
System.out.println("utf-8解码:"+str); //输出乱码;
}
}
/* 输出:
数组的内容:[-2, -1, 0, 97, 78, 45, 86, -3]
Unicode解码:a中国
utf-8解码:??
*/
乱码还原:
乱码还原
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws UnsupportedEncodingException {
String str = "大家好";
byte[] buf = str.getBytes(); //使用gbk进行编码
System.out.println("字节数组:"+ Arrays.toString(buf)); // -76, -13, -68, -46, -70, -61
str = new String(buf,"iso8859-1"); //使用iso8859-1解码
System.out.println(str); //出现乱码
// 问题:出现乱码之后都可以被还原吗? ——可以,解决方案:
byte[] buf2 = str.getBytes("iso8859-1");
str = new String(buf2,"gbk");
System.out.println(str);
}
}