java i o不会的地方_Java I/O 好复杂,傻傻分不清楚,别担心,我们有线索了。。。...
IO 類圖
小帥最近在學Java的IO類庫,這么多類看得小帥人頭昏眼花,常常是學了這個類,忘了那個類,再過一陣子就全忘了。。。
每次用到的時候,小帥都要重新讀文檔,看代碼,如此循環,身心疲憊。
小帥沒辦法只好向好朋友小會求助:IO類庫太復雜了,我毫無頭緒,能不能幫我梳理一下?
小會想了一下,說道:總體來說IO類庫分為兩大類:字節流和字符流,字節流是按字節讀取數據,字符流是按字符讀取數據。
小帥不解:所有的數據在計算機中都是二進制表示的,都用字節來讀取不就行了嗎?
為什么還要加個字符流,我用字節讀出來,再轉成字符不行嗎?
小會說:Java中的字符都是用Unicode表示的,即對應一個數字,也就是碼點。
如果我們用二進制的字節流讀出來是無法看懂的,我們需要用對應的編碼格式(比如:UTF-8,UFT-16等)轉換成我們可讀的字符。
字符流就是專門用來讀寫人們可讀的字符的,這樣會方便很多,一步到位,不用再手工轉換成字符了。
我把IO類都放在一張圖里,這樣看上去就清爽了:
小帥:還是好多類啊。。。小會:別急,我們往下看。
看個例子
我們看一下用字節流,把int數據1到9,寫進txt文件的例子:
FileOutputStream outputStream = new FileOutputStream("text.txt");DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
for(int i = 0; i < 10; i++) {
dataOutputStream.writeInt(i);
}
dataOutputStream.close();
text.txt文件內容:
里面保存的都是二進制數據,但是我們是用int的數據類型寫進去的(dataOutputStream.writeInt(i);),而不是以二進制的格式寫進去的。
小帥疑惑:為什么要用 DataOutputStream寫入int數據呢?
我直接用 FileOutputStream 不能寫嗎?
DataOutputStream有什么作用呢?
小會微微一笑:如果不用DataOutputStream也可以,不過要自己拼成int數據類型的格式,一個int類型占四個字節。
比如1用二進制表示就是 0000 0000 0000 0000 0000 0000 0000 0001,用十六進制表示就是 00 00 00 01。
我們試一下用 FileOutputStream 寫入int數字 0,1,2:
FileOutputStream outputStream = new FileOutputStream("text.txt");
// int 0
outputStream.write(0);
outputStream.write(0);
outputStream.write(0);
outputStream.write(0);
// int 1
outputStream.write(0);
outputStream.write(0);
outputStream.write(0);
outputStream.write(1);
// int 2
outputStream.write(0);
outputStream.write(0);
outputStream.write(0);
outputStream.write(2);
outputStream.close();
寫入結果:
如果用DataOutputStream 寫就是:dataOutputStream.writeInt(0),dataOutputStream.writeInt(1),dataOutputStream.writeInt(2),這樣是不簡單很多呢?
小帥似乎有點懂了:我知道了,DataOutputStream 是對 FileOutputStream 類功能的增強,讓FileOutputStream 類更加強大,起到了裝飾的作用。
小會開心道:你說到重點了,IO類看似凌亂,其實有一個精巧的設計模式,貫穿其中,把這么多類有序的組織起來了。
這個設計模式是理解IO類的鑰匙,你知道是哪一個設計模式嗎?
裝飾者模式?小帥疑惑道。
裝飾者模式
是的,就是裝飾者模式,我以前寫過一篇介紹裝飾者模式的文章,可以點開看看:
裝飾模式--小美的生日蛋糕
。
裝飾者模式的類圖:
OutputStream家族類:
這里的FilterOutputStream類就是裝飾模式中的抽象裝飾類。
它的子類BufferedOutputStream,DataOutputStream,PrintStream就是具體的裝飾類,起到了功能增強的作用。
它們本身并沒有實現寫數據的功能。
看下FilterOutputStream的代碼:
寫數據的功能是靠被修飾的類實現的,這里的OutputStream out 是要從外面傳進來的:
DataOutputStream的writeInt方法實現了功能的增強,可以直接寫int類型的數據:
BufferedOutputStream類實現了緩存的功能增強:
也就是說裝飾類是給主類錦上添花,主類是錦,裝飾類是花,花不能代替錦,主要的功能還得靠“錦”實現的。
清晰起來了
同理我們來看看其他流:
InputStream家族類:
Writer家族類:
小帥一眼看出了問題:奇怪,FilterWriter裝飾類怎么沒有子類呢?是不是Writer家族沒有用裝飾模式呢?
小會微微一笑:不是的,其實還是用了裝飾模式,只是實現的方式有點不一樣,例如OutputStreamWriter類:
其實是對OutputStream類的裝飾,換句話說字符流的底層其實是調用了字節流。
這也很容易理解,因為計算機只能處理二進制數據,本質上還是通過字節流實現的。
Reader家族類:
FilterReader充當了抽象裝飾類,PushbackReader是具體的裝飾類。
同樣的InputStreamReader類其實也實現了裝飾模式:
再看個例子
public static void main(String[] args) throws IOException {
try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("把酒問月·故人賈淳令予問之.txt")))) {
writer.write("青天有月來幾時?我今停杯一問之。");
writer.newLine();
writer.write("人攀明月不可得,月行卻與人相隨。");
writer.newLine();
writer.write("皎如飛鏡臨丹闕,綠煙滅盡清輝發。");
writer.newLine();
writer.write("但見宵從海上來,寧知曉向云間沒。");
writer.newLine();
writer.write("白兔搗藥秋復春,嫦娥孤棲與誰鄰。");
writer.newLine();
writer.write("今人不見古時月,今月曾經照古人。");
writer.newLine();
writer.write("古人今人若流水,共看明月皆如此。");
writer.newLine();
writer.write("唯愿當歌對酒時,月光長照金樽里。");
}
try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("把酒問月·故人賈淳令予問之.txt")))) {
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
}}
輸出:
青天有月來幾時?我今停杯一問之。
人攀明月不可得,月行卻與人相隨。
皎如飛鏡臨丹闕,綠煙滅盡清輝發。
但見宵從海上來,寧知曉向云間沒。
白兔搗藥秋復春,嫦娥孤棲與誰鄰。
今人不見古時月,今月曾經照古人。
古人今人若流水,共看明月皆如此。
唯愿當歌對酒時,月光長照金樽里。
OutputStreamWriter增強了FileOutputStream,讓它擁有了直接寫字符的能力,BufferedWriter增強了OutputStreamWriter,讓它擁有了緩存的能力。
同樣的,InputStreamReader增強了FileInputStream,讓它擁有了直接讀字符的能力,BufferedReader增強InputStreamReader,讓它擁有了緩存的能力。
最后的話
Java的IO類庫以前我也看得一臉懵逼,總是覺得太繁瑣,太難記了。后來學了裝飾者模式才知道,要搞懂Java的IO類庫,其實重點是要搞懂裝飾者模式。
如果不懂裝飾者模式,看多少次也不會理解為什么要這么設計。
當一把鎖被鎖上的時候,你一直盯著鎖看是沒有用的,因為鑰匙肯定不是插在鎖上,一定要去別的地方找鑰匙啊。
總結
以上是生活随笔為你收集整理的java i o不会的地方_Java I/O 好复杂,傻傻分不清楚,别担心,我们有线索了。。。...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一般打胎要多少钱啊,都有什么价位的呢
- 下一篇: java 1 11 111_456756