【一】Java IO流分類及各類簡介(如何將控制檯輸出定向到一個文件、怎麼關閉多層包裝的流)

參考:

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方法之一或寫入時,都會清除輸出緩衝區。

五、怎麼關閉多層包裝的流

流的關閉順序

  1. 一般情況下是:先打開的後關閉,後打開的先關閉
  2. 另一種情況:看依賴關係,如果流a依賴流b,應該先關閉流a,再關閉流b。例如,處理流a依賴節點流b,應該先關閉處理流a,再關閉節點流b
  3. 可以只關閉處理流,不用關閉節點流。處理流關閉的時候,會調用其處理的節點流的關閉方法。JAVA的IO流使用了裝飾模式,關閉最外面的流的時候會自動調用被包裝的流的close()

注意:

  1. 如果將節點流關閉以後再關閉處理流,會拋出IO異常。
  2. 如果關閉了處理流,在關閉與之相關的節點流,也可能出現IO異常。(hadoop編程文件流操作中遇到了。)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章