關於編碼你必須知道的知識和技巧

知其然,知其因此然,完全搞懂編碼,搞定亂碼linux

亂碼問題是全部運維職業生涯中都會遇到的問題,本篇文章帶你探究背後的原理以及解決的技巧服務器

字符編碼

咱們知道計算機只認識二進制數據,其餘格式的數據都須要轉換成二進制才能被計算機處理,也就是說咱們在計算機上看到的文本、視頻、可執行程序等格式的文件,最終都會轉換成二進制數據交給計算機處理網絡

計算機中最小的數據單位是bit,也叫二進制位,每個bit都有0和1兩種狀態,最先的計算機在設計時採用了8個bit做爲一個字節byte,因此一個字節能表示的最大整數就是二進制的11111111,等於十進制的255,想要表示更大的整數就必需要用多個字節,例如兩個字節能夠表示最大的整數就是二進制的1111111111111111,等於十進制的65535運維

因爲計算機是由美國人發明的,在1967年美國人制訂了一套字符編碼規範,規定了包含大小寫字母、數字和一些符號共計128個字符與二進制數字的對應關係,例如回車Enter是二進制是00001101,等於十進制的13,大寫字母A是二進制01000001,等於十進制的65,這一套字符編碼被稱爲ASCII碼,一直沿用至今編碼

英文比較簡單,用128個符號編碼就夠了,可是用來表示中文就不夠了,單單漢字就有超過8萬個,因此就有了針對中文的編碼標準出現,例如咱們常常見到的GB2312,使用兩個字節表示一個漢字,理論上最多能夠表示65535個設計

世界上有上百種語言,每種語言都有本身的編碼標準,例如韓文編碼EUC_KR,日文編碼Shift_JIS,俄文編碼KOI8-R,爲了促進互聯網的發展,Unicode編碼應運而生,Unicode編碼又稱萬國碼、國際碼,它對世界上大部分的文字系統進行了整理,使每個文字符號都有獨一無二的編碼表示,當前Unicode最新的版本爲2019年5月公佈的12.1.0,已經收錄超過13萬個字符,很明顯2個字節已經沒法保證全部字符都獨一無二了,實際上最新的Unicode規定能夠佔用4字節來表示一個字符,理論上最多能表示2的31次方共計2147483648個字符code

Unicode雖然可以解決不一樣編碼出現的問題,使得電腦能夠用更爲簡單的方式來呈現和處理文字,但同時存在着浪費存儲和帶寬的問題,例如大寫字母A,用ASCII碼錶示是01000001,只須要佔一個字節,若是轉換成2個字節的Unicode編碼就變成了0000000001000001,這就極大的浪費了存儲空間,同時對於網絡傳輸消耗也相應增大視頻

爲了解決Unicode的問題,UTF-8編碼方式出現了,UTF-8是一種可變長的編碼方式,它經過前綴碼的方式使Unicode編碼變成了可變長度,關於UTF-8的具體前綴規則簡單總結爲2點以下:blog

  1. 單字節的字符,字節的第一位設爲0,後邊7位爲Unicode碼。對於英語字母,UTF-8編碼和ASCII碼徹底相同
  2. n個字節的字符(n>1),第一個字節的前n位設爲1,第n+1位設爲0,後面字節的前兩位都設爲10,這n個字節的其他空位填充該字符unicode碼,不足用0補足

那就造成了以下的UTF-8編碼規則,其中的x表示的就是要用Unicode填充可用的編碼位unicode

Unicode符號範圍(16進制) UTF-8編碼方式(2進制)
0000 0000 - 0000 007F 0xxxxxxx
0000 0080 - 0000 07FF 110xxxxx 10xxxxxx
0000 0800 - 0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000 - 0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

對於運維咖啡吧的字,其Unicode編碼爲U+54965496在上邊的第三行0000 0800 - 0000 FFFF的範圍內,所以帶入公式計算以下

0101   010010   010110 (最前邊的0即是unicode不足,用0代替)
1110xxxx 10xxxxxx 10xxxxxx (模板,因爲3字節,因此是上邊第三行)
------------------------------------------------------------------
11100101 10010010 10010110 (結果,UTF-8的二進制值)

根據上邊的計算結果得出運維咖啡吧的字UTF-8編碼是111001011001001010010110,轉換爲16進製爲E59296

這即是Unicode與UTF-8的區別,UTF-8可變長就是這麼可變長的,對於英文字母來講UTF-8只佔一個字節,而對於漢字來講他可能就佔了3個字節

終端亂碼

從上邊的編碼介紹中咱們已經知道了不一樣編碼的存在,那麼想要查看一個文件,就必須知道他的編碼方式,用錯誤的編碼方式打開文件就會出現亂碼。

linux下能夠經過file命令查看文件的編碼方式

# file ops-coffee.cn 
ops-coffee.cn: UTF-8 Unicode text

工做中咱們在XSHELL之類的終端中查看文件時出現的亂碼就是系統或文件保存的中文編碼與終端設置的編碼不一致,從而致使解碼錯誤。這裏涉及到三方編碼:

  1. 文件內容或文件名
  2. SHELL環境的語言編碼
  3. XSHELL之類的終端編碼

須要保持三方編碼統一,纔不會有亂碼的出現,其中SHELL環境的語言編碼指的是登錄服務器的SHELL環境時指定的語言編碼,例如LANGLC_*這些變量設置的編碼,XSHELL之類終端編碼就是這類終端軟件設置的編碼

全部遇到的亂碼問題都仔細檢查以上三方編碼是否一致,就能夠順利解決了,同時也建議在工做中制定相應的規範,減小亂碼的發生

處理技巧

1.臨時切換命令輸出語言

正常狀況下命令的輸出結果都遵循系統設置的語言編碼,例如

root@ops-coffee:~# echo $LANG
zh_CN.UTF-8
root@ops-coffee:~# date
2020年 03月 04日 星期三 19:00:55 HKT
root@ops-coffee:~# 
root@ops-coffee:~# 
root@ops-coffee:~# export LANG=en_US.UTF-8
root@ops-coffee:~# echo $LANG
en_US.UTF-8
root@ops-coffee:~# date
Wed Mar  4 19:01:21 HKT 2020

運維腳本中,咱們但願全部系統執行相同命令的時候輸出的結果一致,不要由於字符集不一樣而產生不一樣的結果,那麼如可處理呢?在命令前添加LC_ALL=C

root@ops-coffee:~# date
2020年 03月 04日 星期三 19:05:58 HKT
root@ops-coffee:~# 
root@ops-coffee:~# LC_ALL=C date
Wed Mar  4 19:06:05 HKT 2020

這裏之因此用LC_ALL是由於在LOCALE標準中,LC_ALL優先級最高:LC_ALL>LC_*>LANG

2.批量轉換文件名編碼

有時候咱們會遇到文件名或者目錄名亂碼的問題,尤爲是在不一樣類型系統之間傳輸時,能夠藉助rsync實現批量轉換文件名或目錄名的編碼

rsync -av --iconv=GBK,UTF8 /www/ /nav/

iconv模塊在rsync的3.0之後版本中才支持,用法爲--iconv=<LOCAL>,<REMOTE>,須要注意的是,本地兩個目錄之間同步時LOCAL表示的是源目錄的文件名編碼,經過網絡同步時LOCAL表示本地編碼


掃碼關注公衆號查看更多實用文章

相關文章推薦閱讀:

相關文章
相關標籤/搜索