超硬核詳細學習——深入淺出IO的知識點,值得你學習收藏必備
I/O高級流
昨天我們對高級流中的緩沖流學習,而在IO流的整個大體系中,他還有一些高級流等待著我們來解鎖。
所以話不多說,今天我們先來學習其中一種高級流——轉(zhuǎn)換流。
轉(zhuǎn)換流
在上面,我們知道使用字節(jié)流讀取中文的時候,會出現(xiàn)亂碼的問題,為什么會出現(xiàn)亂碼呢?編碼格式是什么呢。我們在最后使用了字符流進行操作文本,那我們可以做兩者之間的轉(zhuǎn)換嗎?接下來我們就一起詳細的學習這個轉(zhuǎn)換流的由來吧。

可以看圖知道字節(jié)和字符的轉(zhuǎn)換就是通過一定編碼和解碼的操作完成的。為什么會出現(xiàn)亂碼呢?具體一起來看看吧。
字符編碼和解碼
計算機中儲存的信息都是用二進制數(shù)表示的,而我們在屏幕上看到的數(shù)字、英文、標點符號、漢字等字符是二進制數(shù)轉(zhuǎn)換之后的結(jié)果。按照某種規(guī)則,將字符存儲到計算機中,稱為編碼 。反之,將存儲在計算機中的二進制數(shù)按照某種規(guī)則解析顯示出來,稱為解碼 。比如說,按照A規(guī)則存儲,同樣按照A規(guī)則解析,那么就能顯示正確的文本f符號。反之,按照A規(guī)則存儲,再按照B規(guī)則解析,就會導致亂碼現(xiàn)象。
可以用我們所學習的Java解釋為:
String(byte[] bytes, String charsetName): 通過指定的字符集解碼字節(jié)數(shù)組
byte[] getBytes(String charsetName): 使用指定的字符集合把字符串編碼為字節(jié)數(shù)組
復制代碼通俗易懂的來說,不知道大家有沒有看過孫紅雷演過的<潛伏>這部電視劇,就算沒看過,大家也都是知道諜戰(zhàn)片吧。假如,你和我都是間諜,潛伏在敵營中,然后要互相通信。你會直接說一段話,或者寄信然后里面寫著:今晚在天臺見面給我嗎?我保證,如果有你這樣的隊友,潛伏行動不出一天,就直接Over,大家一起玩完。所以我們不能這樣嘛,我們要用的一定格式規(guī)則來進行轉(zhuǎn)換對吧,這樣就算是真的有敵人拿到了這封信,也會懵逼,想著這。。。是什么?然后也會不了了之。大不了今晚不見面,至少保證了我們的存活,安全問題。
那這其中,我們不得先有一定的規(guī)則,可以讓你我進行轉(zhuǎn)換后都能看懂得的表格數(shù)據(jù),我們稱這規(guī)則稱為字符編碼:就是一套自然語言的字符與二進制數(shù)之間的對應(yīng)規(guī)則。
而這表格可以相當于我們參照的轉(zhuǎn)換的規(guī)則,稱之為字符集(編碼表):生活中文字和計算機中二進制的對應(yīng)規(guī)則。
當你寫信的時候,這過程就是把你我看得懂的東西,按我們知道的規(guī)則,進行轉(zhuǎn)換為誰都看不懂的東西,這過程就是編碼。
當我得到你的信的時候,這過程,我不就把這段看不懂的文字進行規(guī)則解析,這過程就是解碼。
這其中要是你喝酒醉寫信給我,不按套路出牌,年輕人不講武德,按另一種規(guī)則來編寫,然后我按我們的規(guī)則來解析,解析完后,都看不懂就一臉問號,這就可以稱之為亂碼了。
所以我們現(xiàn)在先來了解下規(guī)則即字符集:
字符集
Charset:也叫編碼表。是一個系統(tǒng)支持的所有字符的集合,包括各國家文字、標點符號、圖形符號、數(shù)字等。計算機要準確的存儲和識別各種字符集符號,需要進行字符編碼,一套字符集必然至少有一套字符編碼。常見字符集有
ASCII字符集、GBK字符集、Unicode字符集等。當我們知道了編碼格式后,它所對應(yīng)的字符集自然就指定了,所以編碼才是我們最終要關(guān)心的。
以下字符集是我網(wǎng)上找到相對比較全的,如果還想再多了解的話,可以自行百度。畢竟我們是面向百度編程。嘿嘿。
Unicode編碼系統(tǒng)為表達任意語言的任意字符而設(shè)計,是業(yè)界的一種標準,也稱為統(tǒng)一碼、標準萬國碼。它最多使用4個字節(jié)的數(shù)字來表達每個字母、符號,或者文字。有三種編碼方案,
UTF-8、UTF-16和UTF-32。最為常用的UTF-8編碼。UTF-8編碼,可以用來表示Unicode標準中任何字符,它是電子郵件、網(wǎng)頁及其他存儲或傳送文字的應(yīng)用中,優(yōu)先采用的編碼。互聯(lián)網(wǎng)工程工作小組(IETF)要求所有互聯(lián)網(wǎng)協(xié)議都必須支持UTF-8編碼。所以,我們開發(fā)Web應(yīng)用,也要使用UTF-8編碼。它使用一至四個字節(jié)為每個字符編碼,編碼規(guī)則:GB就是國標的意思,是為了顯示中文而設(shè)計的一套字符集。
GB2312:簡體中文碼表。一個小于127的字符的意義與原來相同。但兩個大于127的字符連在一起時,就表示一個漢字,這樣大約可以組合了包含7000多個簡體漢字,此外數(shù)學符號、羅馬希臘的字母、日文的假名們都編進去了,連在
ASCII里本來就有的數(shù)字、標點、字母都統(tǒng)統(tǒng)重新編了兩個字節(jié)長的編碼,這就是常說的"全角"字符,而原來在127號以下的那些就叫"半角"字符了。GBK:最常用的中文碼表。是在
GB2312標準基礎(chǔ)上的擴展規(guī)范,使用了雙字節(jié)編碼方案,共收錄了21003個漢字,完全兼容GB2312標準,同時支持繁體漢字以及日韓漢字等。GB18030:最新的中文碼表。收錄漢字70244個,采用多字節(jié)編碼,每個字可以由1個、2個或4個字節(jié)組成。支持中國國內(nèi)少數(shù)民族的文字,同時支持繁體漢字以及日韓漢字等。
拉丁碼表,別名Latin-1,用于顯示歐洲使用的語言,包括荷蘭、丹麥、德語、意大利語、西班牙語等。
ISO-5559-1使用單字節(jié)編碼,兼容ASCII編碼。ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼)是基于拉丁字母的一套電腦編碼系統(tǒng),用于顯示現(xiàn)代英語,主要包括控制字符(回車鍵、退格、換行鍵等)和可顯示字符(英文大小寫字符、阿拉伯數(shù)字和西文符號)。基本的
ASCII字符集,使用7位(bits)表示一個字符,共128字符。ASCII的擴展字符集使用8位(bits)表示一個字符,共256字符,方便支持歐洲常用字符。ASCII字符集 :
ISO-8859-1字符集:
GBxxx字符集:
Unicode字符集 :
128個
US-ASCII字符,只需一個字節(jié)編碼。拉丁文等字符,需要二個字節(jié)編碼。
大部分常用字(含中文),使用三個字節(jié)編碼。
其他極少使用的
Unicode輔助字符,使用四字節(jié)編碼。
亂碼問題
為什么我們讀取文件會出現(xiàn)亂碼呢,因為我們的編輯器IDEA默認的編碼格式是UTF-8,而如果我們文件格式不是UTF-8格式的話就會讀錯,一般來說,IDEA創(chuàng)建的文件一般也是UTF-8格式,讀取和寫入都不會有任何問題,但是呢,如果我們是在Windows下創(chuàng)建文件的話,其默認是ASCII,會跟隨系統(tǒng)默認的編碼格式,實際就是GBK格式。所以我們文件是GBK格式,而讀取的是UTF-8格式,自然就亂碼了。

代碼演示下亂碼:
public class ReaderTest {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("E:\\demo\\China.txt");
int ch;
while((ch = fr.read()) != -1) {
System.out.println((char) ch);
}
fr.close();
}
}
程序執(zhí)行結(jié)果:
?й?
復制代碼是不是完全看不出什么東西呢,你說你能看出,我就算你厲害。

那我們要如何解決亂碼問題呢,也就是解決編碼問題呢?是時候祭出轉(zhuǎn)換流了。讓你覺得亂碼不是啥問題。
InputStreamReader
InputStreamReader:將字節(jié)流以字符流輸入,是從字節(jié)流到字符流的橋梁。它讀取字節(jié),并使用指定的字符集將其解碼為字符。它的字符集可以由名稱指定,也可以是默認字符集即你的編輯器是什么字符集就是什么字符集。
1. 構(gòu)造方法
public InputStreamReader(InputStream in):創(chuàng)建一個使用默認字符集的字符流。public InputStreamReader(InputStream in, String charsetName):創(chuàng)建一個指定字符集的字符流。演示如下:
public class IpsrTest {
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("e:\\demo\\China.txt"));
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("e:\\demo\\China.txt"), "GBK");
}
}
復制代碼
2. 解決亂碼問題
public class ReadTest2 {
public static void main(String[] args) throws IOException {
String fileName = "E:\\demo\\China.txt";
//創(chuàng)建轉(zhuǎn)換流,默認字符集
InputStreamReader isr = new InputStreamReader(new FileInputStream(fileName));
//創(chuàng)建轉(zhuǎn)換流,指定字符集
InputStreamReader isr2 = new InputStreamReader(new FileInputStream(fileName), "GBK");
int ch;
//默認字符集讀取
while((ch = isr.read()) != -1) {
System.out.print((char) ch);
}
isr.close();
//指定字符集讀取
while((ch = isr2.read()) != -1) {
System.out.print((char) ch);
}
isr2.close();
}
}
程序執(zhí)行結(jié)果:
?й?
中國
復制代碼是不是很好的解決亂碼問題呢,媽媽再也不擔心我看不懂文件啦。有讀取的轉(zhuǎn)換流,當然還有寫出的轉(zhuǎn)換流啦,一起來看看吧。
OutputStreamWriter
OutputStreamWriter:將字節(jié)流以字符流輸入,是從字符流到字節(jié)流的橋梁。使用指定的字符集將字符編碼為字節(jié)。它的字符集可以由名稱指定,也可以是默認字符集即你的編輯器是什么字符集就是什么字符集。
1. 構(gòu)造方法
public OutputStreamWriter(OutputStream in):創(chuàng)建一個使用默認字符集的字符流。public OutputStreamWriter(OutputStream in, String charsetName):創(chuàng)建一個指定字符集的字符流。演示如下:
public class WriterTest {
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
OutputStreamWriter osr = new OutputStreamWriter(new FileOutputStream("e:\\demo\\ChinaOut.txt"));
OutputStreamWriter osr2 = new OutputStreamWriter(new FileOutputStream("e:\\demo\\ChinaOut.txt") , "GBK");
}
}
復制代碼
2. 以指定編碼寫出數(shù)據(jù)
public class WriterTest2 {
public static void main(String[] args) throws IOException {
// 定義文件路徑
String fileName = "E:\\demo\\ChinaOut.txt";
// 創(chuàng)建流對象,默認UTF8編碼
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(fileName));
// 寫出數(shù)據(jù)
osw.write("北極星");
osw.close();
String fileName2 = "E:\\demo\\ChinaOut2.txt";
// 創(chuàng)建流對象,指定GBK編碼
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(fileName2),"GBK");
// 寫出數(shù)據(jù)
osw2.write("叫我了");
osw2.close();
}
}
程序執(zhí)行后結(jié)果:
北極星
叫我啦
復制代碼再看記事本格式,可以發(fā)現(xiàn)如果存儲的是UTF-8,記事本的格式也更改為了UTF-8編碼格式了,而指定了GBK字符集,則記事本的格式為ASCII編碼格式了。
總結(jié)
相信各位看官都對IO流中高級流中的轉(zhuǎn)換流類有了一定了解,期待等待下一章的高級流——打印流教學吧!
當然還有很多流等著下次一起看吧!歡迎期待下一章的到來!
學到這里,今天的世界打烊了,晚安!雖然這篇文章完結(jié)了,但是我還在,永不完結(jié)。我會努力保持寫文章。來日方長,何懼車遙馬慢!
感謝各位看到這里!愿你韶華不負,青春無悔!
注: 如果文章有任何錯誤和建議,請各位大佬盡情留言!如果這篇文章對你也有所幫助,希望可愛親切的您給個三連關(guān)注下,非常感謝啦!

作者:太子爺哪吒
鏈接:https://juejin.cn/post/6995147286112108551
來源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。
