建議先閱讀:Java 編碼那些事(一)
現在說說編碼在Java
中的實際運用。在使用tomcat
的時候,絕大部分同學都會遇到亂碼的問題,查查檔案,google
一下解決方案啥的,都是設定這裡,設定那裡,或者在程式碼中新增編碼方式,雖然最終問題解決了,但是你真的知道這是什麼意思麼?
在平時開發Java
的時候,我們會遇到很多編碼設定,其中包括:
Java檔案的編碼:Java
檔案的編碼表示編寫程式碼得時候,.java
檔案本身的編碼,這個編碼的影響在於將你的寫的程式碼原始檔複製一份,使用其他編輯器開啟,若兩個編輯器的預設編碼方式不一樣,則開啟原始檔就會變成亂碼。一般英文的影響不大,因為大多數編碼都相容ASCII
編碼,但是中文要是編碼不正確,則會亂碼。
IDEA
的設定在:Setting
->Editor
->File Encodings
中設定
JVM編碼:JVM
編碼表示JVM
在讀取String
型別的預設編碼,可以使用Charset.defaultCharset().name()
獲取。可以在JVM
啟動引數中使用-Dfile.encoding=UTF-8
進行設定。
一般需要區分的就是這兩種編碼。下面著重說下JVM
編碼的體現。
熟悉IO
的同學應該都明白這兩個流的區別。一般會出現字元亂碼都在於需要與其他程式進行IO
的時候。
先看看使用位元組流進行讀取檔案的時候:
public static void main(String[] args){ String path="G:\\test.txt"; try(BufferedInputStream inputStream=new BufferedInputStream(new FileInputStream(path))) { for (byte bytes[] = new byte[1024]; inputStream.read(bytes) != -1; ) { String context = new String(bytes); System.out.println(context); } }catch (IOException e){ e.printStackTrace(); } }
然後再G
盤新建一個文字檔案,輸入一段文字。使用預設的格式儲存。
可以檢視輸出:
�����ļ��ļ�
亂碼了,下面來分析一下:
首先這裡是JVM
執行時的編碼,因此和JVM
的編碼設定有關。列印JVM
目前的編碼設定:
System.out.println(Charset.defaultCharset().name());
輸出:UTF-8
找到剛剛新建的檔案test.txt
,點選另存為,可以發現預設編碼為ANSI
,前一篇文章中說過,ANSI
作為windows
系統中的特殊存在,它在簡體中文編碼的情況下預設為GBK
編碼。這便是亂碼的原因,解決方案有兩種:
JVM
啟動項:-Dfile.encoding = GB2312
byte
陣列的時候,指定GB2312
編碼:String context = new String(bytes,"GB2312");
這裡推薦第二種,畢竟UTF8更加通用
問題完美解決。
同理,網路IO
也能通過以上方法解決。
看明白了上面的發現問題和解決問題的流程的同學,下次遇到檔案編碼的問題,相信應該能夠獨立解決問題。
明白了各種編碼問題,現在我們可以著手進行實戰。
第一次使用IDEA
開發Servlet
的時候,大多數都會遇見亂碼問題,包括:
控制檯輸出Tomcat
紀錄檔亂碼
網頁顯示Servlet
返回的中文亂碼
雖然各種Google
後,終於解決了,但是可能依然不明白其中的緣由。下面我們來一探究竟
首先解決Tomcat
紀錄檔亂碼的問題,首先要明白:Tomcat作為一個獨立的程序,IDEA是怎麼獲取到Tomcat紀錄檔的呢?在IDEA
控制檯中的Tomcat
啟動紀錄檔中,我們可以找到一個紀錄檔記錄:
-Dcatalina.base=C:\xxx\.IntelliJIdea2018.3\system\tomcat\xxx
複製選項中的路徑,在資料夾中開啟,進入logs
資料夾,就可以發現這個是tomcat
的紀錄檔檔案輸出路徑,而IDEA正是讀取了這個檔案中的內容輸出到控制檯中,我們可以使用記事本開啟紀錄檔檔案,然後選擇另存為,可以發現檔案的預設編碼是ANSI,也就說在簡體中文下是GBK編碼。
而讀取文字檔案內容一般有兩種方式,第一種是字元流,第二種是位元組流,位元組流可以指定字元編碼也可以通過的JVM啟動引數-Dfile.encoding
指定預設編碼。
明白了上面的問題,我們就能知道為什麼亂碼了,這是因為IDEA的預設編碼和這個紀錄檔檔案的編碼格式不統一導致的。
解決方案很簡單,統一兩個系統的編碼,對於Tomcat
的輸出的紀錄檔檔案,我們可以設定Tomcat
啟動的VM
選項:Edit Configurations
->Server
-> VM options
編輯新增:-Dfile.encoding=UTF-8
設定完Tomcat
編碼後,刪除剛剛路徑中的紀錄檔檔案,重啟Tomcat
服務,再使用記事本開啟剛剛的紀錄檔檔案,另存為我們可以發現,編碼已經變成了UTF-8
。
接下來設定IDEA的編碼,IDEA預設編碼暫時沒有找到查詢方式,我們也可以將其指定為UTF-8
,找到IDEA的安裝路徑,在bin
目錄中可以發現一個名為idea.exe.vmoptions
和idea64.exe.vmoptions
選項,分別開啟,新增-Dfile.encoding=UTF-8
後,重啟IDEA.
完成上面兩步後,再次啟動Tomcat
服務,你會發現紀錄檔已經正常。
注:如果依然發現亂碼,則可能是IDEA快取了當前專案的編碼設定,你可以在當前專案的
.idea
資料夾中找到encoding.xml
檔案,刪除所有不是UTF-8
的編碼設定,重啟IDEA即可。
我們都知道,瀏覽器瀏覽的網頁其實是從伺服器傳送的HTML檔案到瀏覽器中顯示,而傳送的是通過位元組流傳輸,這個過程就涉及到解碼->編碼的過程,在HTTP
協定中,編碼的協定通過Header
中的charset
中設定。
為什麼放
header
,因為HTTP
請求會先解析header
,而且header
一般不會有ascii
無法解析的字元,一般都是英文
網頁亂碼其實很好解決,如果發現在Servlet
中,返回中文給瀏覽器的時候瀏覽器返回的是???
點選F12
,抓包網路後,找到Response Body
中的charset
選項,可以發現charset=ISO-8859-1
也就說預設的Tomcat
使用的編碼是ISO-8859-1
,這是西歐的語言編碼,它是不相容中文的。如果你在Servlet
返回的結果中新增一點法語:Ä ä
或者德語什麼的,你會發現會正常顯示。
charset
的意思便是Tomcat
是以什麼樣的方式編碼位元組,而瀏覽器便會以這樣的編碼方式解碼位元組。
我們可以將charset
修改為相容中文的即可,比如UTf-8
,GB2312
等,建議使用UTF-8
,在Servlet
中,設定編碼的方式為:
response.setCharacterEncoding("UTF-8");
也可以如下:
resp.setContentType("text/html;charset=UTF-8");
建議第一種方式。
到這裡,所有的亂碼問題都已經解決。
其實,亂碼不可怕,可怕的是經歷了這麼多次亂碼卻依然不去了解它。
~~
微信搜尋公眾號:StackTrace,關注我們,不斷學習,不斷提升