Java web 中的中文亂碼問題總結
一、亂碼由來:
大家都知道一句話:“亂碼是因為編碼和解碼方式不一致造成的”。 那麼,我們為什麼要編碼呢?
那就要從計算機底層是如何表示人類語言(包括字母、中文文字、其他符號等等)說起了:
字元:人們使用的記號,抽象意義上的一個符號。 '1', '中', 'a', '$', '¥', ……
位元組:
所以要計算機表示和人類語言符號統一起來,就需要編碼,也就是從字元到位元組或者從位元組到字元的轉換過程,具體各種編碼格式、編碼規則又有不同:
1、ASCII碼(American Standard Code for Information Interchange,美國資訊交換標準程式碼):用1個位元組的低7位來表示共計128個字元,是基於
如下表,有了這個統一的標準之後,大家讀到計算機中某個位元組是:01000001,那麼我們就知道它代表的是大寫字母A;
Bin(二進位制) |
Oct(八進位制) | Dec(十進位制) |
Hex(十六進位制) |
縮寫/字元 |
解釋 |
0000 0000 |
0 |
0 |
00 |
NUT(null) |
空字元 |
0000 0001 |
1 |
1 |
01 |
SOH(start of headline) |
標題開始 |
0000 0010 |
2 |
2 |
02 |
STX (start of text) |
正文開始 |
0000 0011 |
3 |
3 |
03 |
ETX (end of text) |
正文結束 |
0000 0100 |
4 |
4 |
04 |
EOT (end of transmission) |
傳輸結束 |
0000 0101 |
5 |
5 |
05 |
ENQ (enquiry) |
請求 |
0000 0110 |
6 |
6 |
06 |
ACK (acknowledge) |
收到通知 |
0000 0111 |
7 |
7 |
07 |
BEL (bell) |
響鈴 |
0000 1000 |
10 |
8 |
08 |
BS (backspace) |
退格 |
0000 1001 |
11 |
9 |
09 |
HT (horizontal tab) |
水平製表符 |
0000 1010 |
12 |
10 |
0A |
LF (NL line feed, new line) |
換行鍵 |
0000 1011 |
13 |
11 |
0B |
VT (vertical tab) |
垂直製表符 |
0000 1100 |
14 |
12 |
0C |
FF (NP form feed, new page) |
換頁鍵 |
0000 1101 |
15 |
13 |
0D |
CR (carriage return) |
回車鍵 |
0000 1110 |
16 |
14 |
0E |
SO (shift out) |
不用切換 |
0000 1111 |
17 |
15 |
0F |
SI (shift in) |
啟用切換 |
0001 0000 |
20 |
16 |
10 |
DLE (data link escape) |
資料鏈路轉義 |
0001 0001 |
21 |
17 |
11 |
DC1 (device control 1) |
裝置控制1 |
0001 0010 |
22 |
18 |
12 |
DC2 (device control 2) |
裝置控制2 |
0001 0011 |
23 |
19 |
13 |
DC3 (device control 3) |
裝置控制3 |
0001 0100 |
24 |
20 |
14 |
DC4 (device control 4) |
裝置控制4 |
0001 0101 |
25 |
21 |
15 |
NAK (negative acknowledge) |
拒絕接收 |
0001 0110 |
26 |
22 |
16 |
SYN (synchronous idle) |
同步空閒 |
0001 0111 |
27 |
23 |
17 |
ETB (end of trans. block) |
結束傳輸塊 |
0001 1000 |
30 |
24 |
18 |
CAN (cancel) |
取消 |
0001 1001 |
31 |
25 |
19 |
EM (end of medium) |
媒介結束 |
0001 1010 |
32 |
26 |
1A |
SUB (substitute) |
代替 |
0001 1011 |
33 |
27 |
1B |
ESC (escape) |
換碼(溢位) |
0001 1100 |
34 |
28 |
1C |
FS (file separator) |
檔案分隔符 |
0001 1101 |
35 |
29 |
1D |
GS (group separator) |
分組符 |
0001 1110 |
36 |
30 |
1E |
RS (record separator) |
記錄分隔符 |
0001 1111 |
37 |
31 |
1F |
US (unit separator) |
單元分隔符 |
0010 0000 |
40 |
32 |
20 |
(space) |
空格 |
0010 0001 |
41 |
33 |
21 |
! |
歎號 |
0010 0010 |
42 |
34 |
22 |
" |
雙引號 |
0010 0011 |
43 |
35 |
23 |
# |
井號 |
0010 0100 |
44 |
36 |
24 |
$ |
美元符 |
0010 0101 |
45 |
37 |
25 |
% |
百分號 |
0010 0110 |
46 |
38 |
26 |
& |
和號 |
0010 0111 |
47 |
39 |
27 |
' |
閉單引號 |
0010 1000 |
50 |
40 |
28 |
( |
開括號 |
0010 1001 |
51 |
41 |
29 |
) |
閉括號 |
0010 1010 |
52 |
42 |
2A |
* |
星號 |
0010 1011 |
53 |
43 |
2B |
+ |
加號 |
0010 1100 |
54 |
44 |
2C |
, |
逗號 |
0010 1101 |
55 |
45 |
2D |
- |
減號/破折號 |
0010 1110 |
56 |
46 |
2E |
. |
句號 |
00101111 |
57 |
47 |
2F |
/ |
斜槓 |
00110000 |
60 |
48 |
30 |
0 |
數字0 |
00110001 |
61 |
49 |
31 |
1 |
數字1 |
00110010 |
62 |
50 |
32 |
2 |
數字2 |
00110011 |
63 |
51 |
33 |
3 |
數字3 |
00110100 |
64 |
52 |
34 |
4 |
數字4 |
00110101 |
65 |
53 |
35 |
5 |
數字5 |
00110110 |
66 |
54 |
36 |
6 |
數字6 |
00110111 |
67 |
55 |
37 |
7 |
數字7 |
00111000 |
70 |
56 |
38 |
8 |
數字8 |
00111001 |
71 |
57 |
39 |
9 |
數字9 |
00111010 |
72 |
58 |
3A |
: |
冒號 |
00111011 |
73 |
59 |
3B |
; |
分號 |
00111100 |
74 |
60 |
3C |
< |
小於 |
00111101 |
75 |
61 |
3D |
= |
等號 |
00111110 |
76 |
62 |
3E |
> |
大於 |
00111111 |
77 |
63 |
3F |
? |
問號 |
01000000 |
100 |
64 |
40 |
@ |
電子郵件符號 |
01000001 |
101 |
65 |
41 |
A |
大寫字母A |
01000010 |
102 |
66 |
42 |
B |
大寫字母B |
01000011 |
103 |
67 |
43 |
C |
大寫字母C |
01000100 |
104 |
68 |
44 |
D |
大寫字母D |
01000101 |
105 |
69 |
45 |
E |
大寫字母E |
01000110 |
106 |
70 |
46 |
F |
大寫字母F |
01000111 |
107 |
71 |
47 |
G |
大寫字母G |
01001000 |
110 |
72 |
48 |
H |
大寫字母H |
01001001 |
111 |
73 |
49 |
I |
大寫字母I |
01001010 |
112 |
74 |
4A |
J |
大寫字母J |
01001011 |
113 |
75 |
4B |
K |
大寫字母K |
01001100 |
114 |
76 |
4C |
L |
大寫字母L |
01001101 |
115 |
77 |
4D |
M |
大寫字母M |
01001110 |
116 |
78 |
4E |
N |
大寫字母N |
01001111 |
117 |
79 |
4F |
O |
大寫字母O |
01010000 |
120 |
80 |
50 |
P |
大寫字母P |
01010001 |
121 |
81 |
51 |
Q |
大寫字母Q |
01010010 |
122 |
82 |
52 |
R |
大寫字母R |
01010011 |
123 |
83 |
53 |
S |
大寫字母S |
01010100 |
124 |
84 |
54 |
T |
大寫字母T |
01010101 |
125 |
85 |
55 |
U |
大寫字母U |
01010110 |
126 |
86 |
56 |
V |
大寫字母V |
01010111 |
127 |
87 |
57 |
W |
大寫字母W |
01011000 |
130 |
88 |
58 |
X |
大寫字母X |
01011001 |
131 |
89 |
59 |
Y |
大寫字母Y |
01011010 |
132 |
90 |
5A |
Z |
大寫字母Z |
01011011 |
133 |
91 |
5B |
[ |
開方括號 |
01011100 |
134 |
92 |
5C |
\ |
反斜槓 |
01011101 |
135 |
93 |
5D |
] |
閉方括號 |
01011110 |
136 |
94 |
5E |
^ |
脫字元 |
01011111 |
137 |
95 |
5F |
_ |
下劃線 |
01100000 |
140 |
96 |
60 |
` |
開單引號 |
01100001 |
141 |
97 |
61 |
a |
小寫字母a |
01100010 |
142 |
98 |
62 |
b |
小寫字母b |
01100011 |
143 |
99 |
63 |
c |
小寫字母c |
01100100 |
144 |
100 |
64 |
d |
小寫字母d |
01100101 |
145 |
101 |
65 |
e |
小寫字母e |
01100110 |
146 |
102 |
66 |
f |
小寫字母f |
01100111 |
147 |
103 |
67 |
g |
小寫字母g |
01101000 |
150 |
104 |
68 |
h |
小寫字母h |
01101001 |
151 |
105 |
69 |
i |
小寫字母i |
01101010 |
152 |
106 |
6A |
j |
小寫字母j |
01101011 |
153 |
107 |
6B |
k |
小寫字母k |
01101100 |
154 |
108 |
6C |
l |
小寫字母l |
01101101 |
155 |
109 |
6D |
m |
小寫字母m |
01101110 |
156 |
110 |
6E |
n |
小寫字母n |
01101111 |
157 |
111 |
6F |
o |
小寫字母o |
01110000 |
160 |
112 |
70 |
p |
小寫字母p |
01110001 |
161 |
113 |
71 |
q |
小寫字母q |
01110010 |
162 |
114 |
72 |
r |
小寫字母r |
01110011 |
163 |
115 |
73 |
s |
小寫字母s |
01110100 |
164 |
116 |
74 |
t |
小寫字母t |
01110101 |
165 |
117 |
75 |
u |
小寫字母u |
01110110 |
166 |
118 |
76 |
v |
小寫字母v |
01110111 |
167 |
119 |
77 |
w |
小寫字母w |
01111000 |
170 |
120 |
78 |
x |
小寫字母x |
01111001 |
171 |
121 |
79 |
y |
小寫字母y |
01111010 |
172 |
122 |
7A |
z |
小寫字母z |
01111011 |
173 |
123 |
7B |
{ |
開花括號 |
01111100 |
174 |
124 |
7C |
| |
垂線 |
01111101 |
175 |
125 |
7D |
} |
閉花括號 |
01111110 |
176 |
126 |
7E |
~ |
波浪號 |
01111111 |
177 |
127 |
7F |
DEL (delete) |
刪除 |
2、ISO-8859-1: ISO組織在ASCII碼基礎上擴充套件到256個字元,制定的標準,涵蓋了大多數西歐語言字元。
3、GB2312:全稱是《資訊交換用漢字編碼字符集》,是由中國國家標準總局1980年釋出,1981年5月1日開始實施的一套國家標準;採用雙位元組編碼,共包含682個符號和6763個漢字。
4、GBK:全稱《漢字內碼擴充套件規範》(GBK即“國標”、“擴充套件”漢語拼音的第一個字母),擴充套件的GB2312,向下相容GB2312,也就是說,GB2312編碼的,用GBK解碼是沒問題的,不會出現亂碼;
5、GB18030:應用不廣泛,相關資料後續有機會補上;
6、UTF-16: 說到UTF(Unicode TransferFormat :把Unicode轉做某種格式),就必須先說一說Unicode(Universal code 統一碼),Unicode是ISO組織建立的一個世界統一性的字典,但是不是具體的編碼格式標準。 UTF-16是一個實現版本,但是它使用定長2個位元組來表示所有的字元。值得一提的是,定長表示大大簡化了字串的操作,很適合本地磁碟和記憶體之間使用,這是Java以UTF-16作為記憶體的字元儲存格式的一個重要原因。
7、UTF-8: 雖然UTF-16在字元表示上簡單方便,但是在網路傳輸中同時也造成了儲存空間的浪費、網路傳輸流量的增加,這是其缺點。
UTF-8採用了變長的技術,不同型別的字元,可以由1~6個字元來表示,適合網路傳輸。基本編碼規則如下:
小結: 這下我們就知道亂碼怎麼來的:假設某字元是用GBK的編碼規則編碼的,如果我用ISO-8859-1的規則去解碼,那麼原本GBK兩個位元組代表的一個字元,在ISO-8859-1的規則下就會拆成2個單獨的位元組,也就不可能正確翻譯出原來的字元是什麼了。
二、Java中亂碼產生的可能情況(需要字元和位元組轉換的場景):
1、I/O操作:包括磁碟I/O和網路I/O(關於Java中處理I/O問題,我將會以另一篇博文呈現)
2、在記憶體中操作的編碼:也就是資料型別轉換操作。
如下,從列印結果可以看到,編碼格式保持一致的重要性。
String str = "我是中文";
byte[] b = str.getBytes("UTF-8");
String str1 = new String(b,"UTF-8");
System.out.println(str1); //我是中文
String str2 = new String(b,"GBK");
System.out.println(str2);//鎴戞槸涓枃
三、後記:
Java web 中涉及的編解碼,同樣後面會在另外一篇博文中呈現。
相關部落格:Eclipse console 輸出中文亂碼問題