Java中的IO流 – 入門篇
大家好啊,我是湯圓,今天給大家帶來的是《Java中的IO流-入門篇》,希望對大家有幫助,謝謝
由於Java的IO類有很多,這就導致我剛開始學的時候,感覺很亂,每次用到都是上網搜,結果每次用完就忘;
後來沉下心去看書學習,才明白都是有規律的;
這裡先做個簡單的介紹,作為入門級教程,後面還有很多要學習的,有空再整理吧。
簡介
文件IO流,主要有兩種方式
-
位元組流:基於普通的Java對象,僅適用於Java程式之間的讀寫
-
字元流:基於普通的文本字元串,不僅適用於Java程式之間的讀寫,也適用於Java程式和其他語言程式之間的讀寫
本例中用到的相關類如下:

所有的讀寫操作都是針對記憶體而言的,因為程式就是運行在記憶體中
讀操作就是從磁碟文件或網路流讀到記憶體,對於記憶體而言就是Input
寫操作就是從記憶體寫到磁碟文件或網路流,對於記憶體而言就是Output
下面分別介紹這兩種方式
位元組流:基於普通的Java對象
位元組流的讀和寫都是基於Java程式而言,比如在一個機器上的Java程式寫入一個對象到文件,然後傳輸到另一個機器上的Java程式去讀取文件中的對象
寫入Java對象時,會先將Java對象序列化(對象轉為位元組),然後寫入
讀取Java對象時,會先將Java對象反序列化(位元組轉為對象),然後讀取
寫對象
將對象寫入到文件中,需要先把對象序列化,然後再把序列化後的位元組寫入到文件中;
序列化就是將對象的屬性資訊轉為一系列位元組(不包括transient 類型的屬性,下面會介紹)
大概流程如下所示:

讀對象
將對象從文件中讀出來,需要先反序列化,然後再轉為對應的Java對象,並恢復對象屬性值
反序列化就是將一系列位元組轉為真實的對象實例(不包括transient類型的屬性)
大概流程如下所示:

transient
該修飾符 字面意思是瞬時的,短暫的
用在對象的屬性上,就表示這個屬性是暫時有效的,等序列化的時候會失效
在反序列化的時候,這個屬性就會為null(如果屬性是對象引用)或基礎類型的默認值(如果屬性是基礎類型)
比如密碼等比較隱私的屬性,我們就可以設置為transient,這樣就不會在傳輸過程中被被人攔截,從而破解出密碼
程式碼
public class ObjectIoDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
InnerObject object1 = new InnerObject(10);
String filename = "object.bin";
writeObjectFun(filename, object1);
InnerObject objectReturn = (InnerObject) readObjectFun(filename);
System.out.println(objectReturn);
}
// 寫對象 到指定文件
public static void writeObjectFun(String filename, Object o) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream(filename);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(o);
// 關閉流,fileOutputStream會一併關閉
objectOutputStream.close();
}
// 讀對象 從指定文件
public static Object readObjectFun(String filename) throws IOException, ClassNotFoundException {
FileInputStream fileInputStream = new FileInputStream(filename);
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
Object o = objectInputStream.readObject();
// 關閉流,fileInputStream會一併關閉
objectInputStream.close();
return o;
}
}
class InnerObject implements Serializable{
如果要寫入的Java對象沒有序列化,則會報錯如下
Exception in thread "main" java.io.NotSerializableException: com.jalon.basic.io.InnerObject
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at com.jalon.basic.io.ObjectIoDemo.writeObjectFun(ObjectIoDemo.java:28)
at com.jalon.basic.io.ObjectIoDemo.main(ObjectIoDemo.java:19)
字元流:基於普通文本字元串
字元流寫入到文件中的數據,是作為通用文本數據來處理的,這樣Java程式和其他程式都可以去讀寫這個文件
寫文本
大致流程如下:

讀文本
大致流程如下:

BufferedReader和BufferedWriter的作用
為什麼要用緩衝區呢?直接用FileReader和FileWriter不也可以嗎?
如果直接用FileWriter和FileReader是可以運行,只不過效率會比較低,因為每一次的讀寫都是針對磁碟操作的;
而BufferedWriter和BufferedReader這兩個緩衝區可以減少磁碟的讀寫次數;
BufferedReader:程式可以從磁碟一次性讀很多數據到緩衝區,再從緩衝區一次次讀,等緩衝區為空時再去磁碟讀;
BufferedWriter:程式可以寫多次到緩衝區,等快取區滿了再一次性寫入到磁碟中
程式碼
public class TextIoDemo {
public static void main(String[] args) throws IOException {
String filename = "string.txt";
writeString(filename, "hello world");
String res = readString(filename);
System.out.println(res);
}
// 寫字元串到指定文件
public static void writeString(String filename, String content) throws IOException {
FileWriter fileWriter = new FileWriter(filename);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write(content);
bufferedWriter.close();
}
// 從指定文件讀取字元串
public static String readString(String filename) throws IOException {
FileReader fileReader = new FileReader(filename);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line = "";
StringBuilder stringBuilder = new StringBuilder();
while ((line=bufferedReader.readLine())!=null){
stringBuilder.append(line);
}
bufferedReader.close();
return stringBuilder.toString();
}
}
總結
IO流分為位元組流和字元流
如果讀寫兩邊都是Java程式,則推薦用位元組流,序列化和反序列化很方便
如果一邊是Java程式,另一邊是其他語言的程式,則推薦用字元流,讀寫的內容都是文本格式,方便解析
上面只是列出了個別讀寫類,Java中讀寫類還有很多,大家感興趣的可以去java.io下查看

參考
-
《Head First Java》(第二版)
-
《Java 核心技術卷一》(第十版)
-
《Java 編程思想》(第四版)
後記
