參考:
https://blog.csdn.net/jingzi123456789/article/details/72123937
https://blog.csdn.net/sinat_42483341/article/details/97261619
一、按數據流的方向分類
1.輸入流
通常類的名字中有Input或者reader
2.輸出流
通常類的名字中有output或者writer
二、按處理數據單位分類
1.字節流
傳輸過程中,傳輸數據的最基本單位是字節的流。
字節流的類通常以stream結尾。
字節流在操作時本身不會用到緩衝區(內存),是對文件本身直接操作的。
關於這個特性舉個例子:用OutputStream往一個文件裏面寫東西,out.write(b)後不用flush()也不用out.close()就能立即在文件中看到寫入的內容
注意:並不是所有的字節流都不使用緩衝區,比如BufferedOutputStream和BufferedInputStream用到了緩衝區
2.字符流
傳輸過程中,傳輸數據的最基本單位是字符的流。
數據流中最小的數據單元是字符, Java中的字符是Unicode編碼,一個字符佔用兩個字節。
字符流的類通常以reader和writer結尾。
字符流在操作時使用了緩衝區,通過緩衝區在操作文件,關閉字符流時會強制性地將緩衝區中的內容進行輸出。
關於這個特性舉個例子:用Writer往一個文件裏面寫東西,out.write(str)後如果不調用close()不調用flush(),文件中是看不到這次寫的內容的。
三、按功能不同分類
1.節點流
從一個特定的數據源(節點)讀寫數據,如內存、文件。
節點流的類型
節點類類型 | 字符流 | 字節流 |
File(文件) 對文件進行讀、寫操作 |
FileReader FileWriter |
FileInputStream FileOutputStream |
Memory Array 從/向內存數組讀寫數據 |
CharArrayReader CharArrayWriter |
ByteArrayInputStream ByteArrayOutputStream |
Memory String 從/向內存字符串讀寫數據 |
StringReader StringWriter |
|
Pipe(管道) 實現管道的輸入和輸出(進程間通信) |
PipedReader PipedWriter |
PipedInputStream PipedOutputStream |
2.處理流
處理流是連接在已存在的流(節點流或處理流)之上,通過對數據的處理爲程序提供更豐富的讀寫功能
處理流的類型
處理類型 | 字符流 | 字節流 |
Buffering緩衝流 在讀入或寫出時,對數據進行緩存,以減少I/O的次數 |
BufferedReader BufferedWriter |
BufferedInputStream BufferedOutputStream |
Filtering 濾流 在數據進行讀或寫時進行過濾 |
FilterReader FilterWriter |
FilterInputStream FilterOutputStream |
Converting between Bytes and Characters 轉換流 按照一定的編碼/解碼標準將字節流轉換爲字符流,或進行反向轉換(Stream到Reader) |
InputStreamReader OutputStreamWriter |
|
Object Serialization 對象流 |
ObjectInputStream ObjectOutputStream |
|
DataConversion數據流 按基本數據類型讀、寫(處理的數據是Java的基本類型(如布爾型,字節,整數和浮點數)) |
DataInputStream DataOutputStream |
|
Counting計數流 在讀入數據時對行記數 |
LineNumberReader | LineNumberInputStream |
Peeking Ahead預讀流 通過緩存機制,進行預讀 |
PushbackReader | PushbackInputStream |
Printing打印流 包含方便的打印方法 |
PrintWriter | PrintStream |
3.示例
將鍵盤錄入的數據保存到一個文件中,輸入“over”時表示錄入結束
1.Converting between Bytes and Characters 轉換流和Buffering緩衝流
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw=new BufferedWriter(new FileWriter("readin.txt"));
String line=null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line)) break;
bufw.write(line);
bufw.newLine();
}
bufw.close();
bufr.close();
2.DataConversion數據流示例
FileOutputStream fout = new FileOutputStream("demo.txt",true);
BufferedOutputStream bout = new BufferedOutputStream(fout);
DataOutputStream dout = new DataOutputStream(bout);
/*DataOutputStream,BufferedOutputStream,FileOutputStream這裏使用了流棧。*/
dout.writeInt(110);
dout.writeUTF("hello,中國");
dout.writeFloat(3.14f);
dout.writeChar(97);/*97對應的是'a'*/
dout.close();/*如果正在使用一個流棧,程序關閉最上面的一個流也就自動的關閉了棧中的所有底層流。*/
FileInputStream fin = new FileInputStream("demo.txt");
BufferedInputStream bin = new BufferedInputStream(fin);
DataInputStream din = new DataInputStream(bin);
int i = din.readInt();
String str = din.readUTF();
float f = din.readFloat();
char c = din.readChar();
fin.close();/*如果正在使用一個流棧,程序關閉最上面的一個流也就自動的關閉了棧中的所有底層流。*/
System.out.println("int:"+i+"\nString:"+str+"\nfloat:"+f+"\nchar:"+c);
注意
int i = din.readInt();
String str = din.readUTF();
float f = din.readFloat();
char c = din.readChar();
/*此段代碼的順序不能亂,要保證先寫入的先讀出來的原則,否則會出現錯誤。
* 因此,我們在寫代碼的時候,我們必須:
* 要麼爲文件中的數據採用固定的格式;
* 要麼將額外的信息保存到文件中,以便能夠對其進行解析以確定數據的尋訪位置。
*/
四、如何將控制檯輸出定向到一個文件
public class Printer {
public static void main(String[] args) throws FileNotFoundException {
// 普通的控制檯輸出
PrintStream ps = System.out;
ps.println("before");`在這裏插入代碼片`
// 將輸出重定向到文件
ps = new PrintStream(new BufferedOutputStream(new FileOutputStream("print.txt", true)), true);
System.setOut(ps);
System.out.println("change");
// 返回到控制檯輸出
System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)), true));
System.out.println("change back");
}
}
有類似的方法(setIn和setErr)用於更改標準輸入和錯誤流。
如果append是true,則流將追加到現有文件,而不是將其截斷。如果autoflush是true,則每當寫入字節數組,調用println方法之一或寫入時,都會清除輸出緩衝區。
五、怎麼關閉多層包裝的流
流的關閉順序
- 一般情況下是:先打開的後關閉,後打開的先關閉
- 另一種情況:看依賴關係,如果流a依賴流b,應該先關閉流a,再關閉流b。例如,處理流a依賴節點流b,應該先關閉處理流a,再關閉節點流b
- 可以只關閉處理流,不用關閉節點流。處理流關閉的時候,會調用其處理的節點流的關閉方法。JAVA的IO流使用了裝飾模式,關閉最外面的流的時候會自動調用被包裝的流的close()
注意:
- 如果將節點流關閉以後再關閉處理流,會拋出IO異常。
- 如果關閉了處理流,在關閉與之相關的節點流,也可能出現IO異常。(hadoop編程文件流操作中遇到了。)