大家好啊,我是湯圓,今天給大家帶來的是《Java中的IO流-入門篇》,希望對大家有幫助,謝謝
由於Java的IO類有很多,這就導致我剛開始學的時候,感覺很亂,每次用到都是上網搜,結果每次用完就忘;
后來沉下心去看書學習,才明白都是有規律的;
這里先做個簡單的介紹,作為入門級教程,后面還有很多要學習的,有空再整理吧。
簡介
文件IO流,主要有兩種方式
-
字節流:基於各種文件,包括普通文本txt,音頻文件mp3,視頻文件mp4等
-
字符流:基於普通的文本字符串,比如普通文本txt等
本例中用到的相關類如下:
所有的讀寫操作都是針對內存而言的,因為程序就是運行在內存中
讀操作就是從磁盤文件或網絡流讀到內存,對於內存而言就是Input
寫操作就是從內存寫到磁盤文件或網絡流,對於內存而言就是Output
下面分別介紹這兩種方式
字節流
本例子,字節流中主要講的是ObjectInputStream和ObjectOutputStream,這兩個類是針對普通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 編程思想》(第四版)
后記