目錄
一 IO流
Java中I/O操作主要是指使用java.io
包下的內容,進行輸入、輸出操作。I 是輸入(input)也叫做讀取數據,O是輸出(Output)也叫做作寫出數據。
IO流根據數據的流向分爲輸入流和輸出流
-
輸入流 :把數據從其他設備讀入到內存中的流
-
輸出流 :把數據從內存中寫出到其他設備的流
根據數據類型可以分爲字節流和字符流
-
字節流 :以字節爲單位,讀寫數據的流。
-
字符流 :以字符爲單位,讀寫數據的流
這兩種分類正好和Java中各種流的四個頂級父類相對應,如下
輸入流 | 輸出流 | |
---|---|---|
字節流 | 字節輸入流 InputStream | 字節輸出流 OutputStream |
字符流 | 字符輸入流 Reader | 字符輸出流 Writer |
1、1 字節流、字符流
因爲四種流的子類功能大致相同,所以這裏用一個表格來展示四種流的常用子類
|
字節輸入流 |
字節輸出流 |
字符輸入流: |
字符輸出流: |
超類 |
InputStream |
OutputStream |
Reader |
Writer |
常用子類 |
FileInputStream 構造方法 FileInputStrea(File file) FileInputStream(String path) |
FileOutputStream 構造方法: FIleOutputStream(File file,boolean append) FIleOutoutStream(String name,boolean append) 後面的參數不寫默認爲false,false爲覆蓋,true爲拼接
|
FileReader 構造方法: FileReader(File file) FileReader(String path) |
FileWriter 構造方法 FileWriter(File file, boolean append) FileWriter(String fileName, boolean append) 後面的參數不寫默認爲false,false爲覆蓋,true爲拼接 |
常用方法 |
read 讀字節 read() 讀單個字節,返回讀到的字節 read(byte[] bytes)讀取一個字節數組 一次讀一個固定長度的字節數組,將讀取到的內容存到bytes中,返回讀取的個數 |
write寫字節
|
read 讀字符 read()讀單個字符 read(char[] chars)讀取一個字符數組,,一次讀取一個固定長度的字符數組,將讀取到的內容存到chars中,返回讀取的個數 |
write 寫字符 write(char[] chs)寫字符數組 write(char[] int start,int length)寫字符數組的一部分 flush()刷新,字符輸出流必須刷新,不刷新數據不進入到數據墓地 close()關閉資源,在關閉前,會自動刷新一次 |
注意:
1、輸入流以字節輸入流爲例,使用read()方法 讀字節,讀完後,會返回-1,可以一次爲文件讀完與否的依據
2、萬物皆字節,所以使用字節流保證了數據的安全性,而使用字符流會造成字符丟失的情況,建議文本使用字符流讀取,非文本使用字節流讀取
3、輸出流,以字節輸出流爲例,輸出流往外寫東西需要一個文件作爲實例化參數,如果存在直接寫,或追加、或覆蓋,如果不存在,系統會直接創建
4、輸出流的輸出需要調用flush()方法刷新一下將數據寫出,而close()方法在關閉系統資源時會自動的刷新一下。
5、close()方法:java本身沒有操作文件的功能,但是可以調用操作系統的功能實現文件的讀寫,而操作完,需要告訴操作系統關閉文件操作功能。close()就是這個作用!
1、1、1使用字節流實現文件複製
package com.heronsbill.stremtest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
/**
* @Author: heronsbill
* @DATA: 2019/8/26
*/
public class Test4 {
public static void main(String[] args) throws Exception {
// 加載jpg圖片
File fileRead = new File("D:\\aaa\\IMG_20160721_212853_HDR.jpg");
// 圖片輸出路徑
File fileWrite = new File("D:\\aaa\\aaa\\def.jpg");
// 讀圖片信息
FileInputStream fileInputStream = new FileInputStream(fileRead);
// 寫圖片信息
FileOutputStream fileOutputStream = new FileOutputStream(fileWrite, true);
// 定義字節數組,用來接收FileInputStream讀到的字節
long a = System.currentTimeMillis();
int len = 0;
int i = 0;
// 當讀完的時候會返回-1
while (( len = fileInputStream.read()) != -1) {
fileOutputStream.write(len);
System.out.println(i++);
}
long b = System.currentTimeMillis();
fileOutputStream.close();
fileInputStream.close();
System.out.println(b-a);
}
}
最後一個4.48M的圖片經歷61970ms(62s)實現了複製功能,我們可以看到使用字節流一個一個的取讀取字節來實現複製功能效率太低,我們可以通過添加定長的字節數組(長度越高,速度越快,但需要根據電腦配置進行設置,一般定義爲1024位的長度)來接收輸入流讀取的信息的方式來提高效率
byte[] bytes = new byte[1024];
int i = 0;
// 當讀完的時候會返回-1
while (fileInputStream.read(bytes) != -1) {
fileOutputStream.write(bytes);
System.out.println(i++);
fileOutputStream.flush();
}
這樣,時間就大大縮短到了122ms,可是在實際應用中這樣的速度仍然是慢,那麼緩衝流就是用來解決傳統字節流,字符流讀取速度過慢的一些類
1、2 緩衝流
實現高效的讀寫
四種緩衝流
字節緩衝流:BufferedInputStream(InputStream in),BufferedOutputStream(OutputStream out)
字符緩衝流:BufferedReader(Reader in),BufferedWriter(Writer out)
字符緩衝流的特有方法:
BufferedReader:public String readLine():讀一行文字,返回讀取的內容,當返回null時,就是讀完了
BufferedWriter:public void newline():寫行分隔符,行分隔符由系統定義(\n或\r\n等等),也就是換行
在讀取配置文件時使用緩衝流 BufferedReader的readLine()方法直接讀取一行,是一個相當不錯的方法
下面用緩衝流實之前的文件的複製
package com.heronsbill.stremtest;
import java.io.*;
/**
* @Author: heronsbill
* @DATA: 2019/8/26
*/
public class Test6 {
public static void main(String[] args) throws Exception {
// 加載jpg圖片
File fileRead = new File("D:\\aaa\\IMG_20160721_212853_HDR.jpg");
// 圖片輸出路徑
File fileWrite = new File("D:\\aaa\\aaa\\niuniu.jpg");
// 讀圖片信息
FileInputStream fileInputStream = new FileInputStream(fileRead);
// 寫圖片信息
FileOutputStream fileOutputStream = new FileOutputStream(fileWrite, true);
// 創建緩衝流
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
// 定義接收字節的數組
byte[] b =new byte[1024];
long l = System.currentTimeMillis();
// 遍歷打印
while (bufferedInputStream.read(b)!=-1){
bufferedOutputStream.write(b);
}
long l1 = System.currentTimeMillis();
// 輸出複製所用時間
System.out.println(l1-l);
// 關閉資源
bufferedOutputStream.close();
bufferedInputStream.close();
fileOutputStream.close();
fileInputStream.close();
}
}
同樣是4.48M的圖片複製下來只需要23ms
1、3 轉換流
轉換流的實際應用,是將一種編碼格式的流轉換另一種編碼格式,它是字節與字符之間的橋樑(如下圖),
InputStreamReader 字節流到字符流的橋樑,是一個解碼的過程
InputStreamReader(InputStream in):創建一個使用默認字符集的輸入轉換流
InputStreamReader(InputStream in , String charsetName)創建一個指定字符集的輸入轉換流
OutputStreamWriter 字符流到字節流的橋樑,是一個編碼的過程
OutputStreamWriter(OutputStream out):創建一個使用默認字符集的輸出轉換流
OutputStreamWriter(OutputStream out,String charsetName):創建一個指定字符集的輸出轉換流
1、4 序列化流
Java提供的一種序列化機制。用一個字節序列可以表示一個對象,該字節序列包含該對象的數據,對象的類型和對象中存儲的屬性等信息。字節序列寫出到文件之後,就相當於在文件中持久保持了一個對象的信息
反之,該字節序列還可以從文件中讀取回來,重構對象,對他進行反序列化。對象的數據,對象的類型、對象存儲的數據信息,都可以用來在內存中創建對象
序列化
ObjectOutStream類:將java對象的原始數據類型寫出到文件,實現對象的持久存儲
構造方法:
public ObjectOutputStream(OutputStream out)
屬性方法:
writeObject(Object obj) 寫對象
反序列化
ObjectInputStream類:將之前使用ObjectOutputStream序列化的原始數據恢復爲對象
構造方法:
public ObjectInputStream(InputStream in)
屬性方法
readObject():讀對象
需要注意的是,一個對象要想實現序列化,反序列化,必須實現序列化接口----Serializable,Serializable是一個標記接口(沒有方法的接口),不實現此接口的類將不會使任何狀態序列化或反序列化,會拋出NotSerializableException;而且實現序列化的對象類的所有屬性必須是可序列化的,即不被static和transient修飾,反之,如果一個屬性不需要可序列化,則該屬性必須用transient註明是瞬態的
1.5 打印流
打印流指PrintStream類
平時練習輸出語句信息的的時候會用 System.out.println();進行輸出,這其實是調用系統默認的輸出流,將信息輸出在控制檯上,而通過PrintStream對象,指定輸出路徑,再調用System.setOut(ps)方法就可以控制輸出打印的位置
創建打印流對象:
PrintStream ps= new PrintStream(“數據目的”)
調用write()方法(因爲PrintStream是OutputStream的子類)
ps.write(100)//這個輸出的是100在ascii表中對應得字符d
ps.print(亂七八糟一堆)//原生輸出
擴:
Syetem.out.println(亂七八糟一堆)的深入理解
PrintStream ps = new PrintStream(Filename filename)
//改變輸出的流向
System.setOut(ps);
System.out.println(97)//這個97就不再輸出到控制檯了,而是輸出到filemname中
二 、總結:
不同流有不同的功能,但方法都有互通性,可以通過比較的方式進行學習,加深理解。萬物皆字節,所有在實際操作中字節流的使用要不字符流多,而使用字節流,也可以有效的避免字節丟失,字節流配合緩存流,又能提高效率。不同系統、文件間的轉換勢必要考慮編碼問題,實際工作中確實會提前將編碼格式設置好,但是瞭解轉換流,並熟練使用,對理解程序運行的原理,過程有很大幫助。
能力尚淺,有待進步,如有不足,不吝賜教!