摘要:下面我們使用字節輸入輸出流來說明這個問題輸入流一般是由對象如建立的,當新建一個時,對象建立了一個包含有數據的管道其實就是我們所說的這個流并將對象存儲的數據輸入到管道中,因此管道里的數據流就是對象內的數據。
流的原理:
一連串有順序的數據系列可以看成是一個流。
輸入輸出流:數據從IO輸入到程序的流是輸入流,數據從程序輸出到IO的流是輸出流。
下面我們使用字節輸入輸出流來說明這個問題:
輸入流 InputStream一般是由javaio對象(如File)建立的,當新建一個InputStream時,io對象建立了一個包含有數據的管道(其實就是我們所說的這個“流”)并將io對象存儲的數據輸入(input)到管道中,因此管道里的數據流就是io對象內的數據。當調用InputStream數據流的read方法時,管道里的數據流讀出到內存對象中(比如數組或者字符串),注意,讀出的比特流將會被移除,具體能可讀的數據的量可用available函數來查看;
輸出流 OutputStream也是由javaio對象(如File)建立的,當新建一個OutputStream時,io對象建立了一個包含有數據流的管道并建立起io對象和管道的映射。 當調用OutputStream數據流的write方法時,內存對象里的數據就會流入管道里,而管道里的數據流輸出(output)到io對象中,flush函數將促使數據緩沖區中的數據被寫入到io設備(文件本身)中區;
public class FilesTest { public static void main(String[] args) throws IOException { File file = new File(“1.txt"); InputStream inputStream = new FileInputStream(file); byte[] buffer = new byte[1024]; while(inputStream.read(buffer)!=-1) System.out.println(new String(buffer)); inputStream.close(); } }
在這個例子里我們可以充分看出輸入流創建和輸入的過程,首先創建一個File對象來映射IO上的這個文件,依據這個File對象來創建輸入流InputStream對象,注意,創建過后輸入流里按序存儲著IO文件里的數據內容(這個過程中可能InputStream并不是其存儲作用的,因為若果這樣大文件內的數據一次性存儲可能會爆內存,所以這個過程應該是InputStream映射到IO文件),調用輸入流InputStream對象的read方法,即可將流內的數據輸入到程序中的之前創建的對象內,最終在使用完后關閉作為有限資源的輸入流。這個過程完成了數據由IO對象輸入到程序。
注意:如果是上次沒有讀完輸入流內的內容,那么下一次程序到InputStream去讀的時候是接著上次的結尾讀的,這個可以根據InputStream對象的available方法看出來,所以在這個角度來看輸入流就像是文件里的索引指針一樣。
public class FilesTest { public static void main(String[] args) throws IOException { File file = new File("test.txt"); OutputStream outputStream = new FileOutputStream(file); byte[] buffer = "hello".getBytes(); outputStream.write(buffer); outputStream.close(); } }
在這個例子里我們可以充分看出輸出流創建和輸出的過程,首先創建一個File對象來映射IO上的這個文件,依據這個File對象來創建輸出流OutputStream對象,調用輸出流OutputStream對象的write方法,即可將程序對象中的數據寫到輸出流中然后從輸出流輸出到IO文件中去,最終在使用完后關閉作為有限資源的輸出流。這個過程完成了數據由程序輸出到IO文件中。
字符輸入輸出流的道理是一樣的,只不過字符流是直接處理字符的,而字節流的處理單位是字節。
read和write的API大同小異,無非就是把流里面的內容和緩沖區通過這些函數來進行交換。
既然可以依據IO文件來創建流在文件和程序之間交換數據,那么我們可不可以從中間再加入一個流來作為中轉處理一下數據呢?這個流的流構成的多流鏈稱之為“流對象鏈”,這個過程說明不是所有的流都是直接和原始數據源打交道的,所以有如下定義:
節點流(Node Stream)直接連接到數據源,直接從IO文件上輸入或輸出數據;
處理流(Processing Stream)是對一個已存在的流的連接和封裝,通過所封裝的流的功能調用實現增強的數 據讀寫功能,它并不直接連到數據源。
public class FilesTest { public static void main(String[] args) throws IOException { FileOutputStream outputStream = new FileOutputStream("1.txt"); PrintStream printStream = new PrintStream(outputStream); printStream.print("xxx"); printStream.close(); outputStream.close(); } }
這個過程的原理如下圖所示:
在這個例子里我們可以充分看出流對象鏈形成的過程,首先創建一個File對象來映射IO上的這個文件,依據這個File對象來創建輸出流OutputStream對象,利用這個輸出流對象再創建一個PrintStream對象來鏈接輸出流對象,調用PrintStream對象的print方法,即可將程序對象中的數據寫到PrintStream中然后再輸出到IO文件中去,最終在使用完后關閉作為有限資源的流。這個過程完成了數據由程序輸出到IO文件中。
流中的緩沖技術在內存中開辟一塊區域,稱為緩沖區,當緩沖區滿時一次寫入到磁盤中,提高了I/O的性能。和一般的輸入輸出流相比,這樣的帶有緩沖區的流可以做到更好的IO性能,在帶緩沖的輸出流時由于緩沖區的存在,需要在最后強制使用flush函數將緩沖區中剩余的內容全部輸出到IO設備中去。
public class FilesTest { public static void main(String[] args) { try { byte[] data = new byte[1]; File srcFile = new File("1.txt"); File desFile = new File("2.txt"); BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(srcFile)); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(desFile)); while (bufferedInputStream.read(data) != -1) { bufferedOutputStream.write(data); } bufferedOutputStream.flush(); bufferedInputStream.close(); bufferedOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
這里表現的是這個過程,IO文件里的數據經過文件輸入流FileInputStream對象流入緩沖輸入流BufferedInputStream對象,之后所有的數據(在數據量較小的時候,一般是小于8K時,后面會討論到)流入輸入流的緩沖區,之后每次在讀取的時候都是直接從緩沖區讀到臨時的數組中去而不是再從流讀入,然后臨時數組的數據在write函數的作用下寫到輸出流的緩沖區中去,緩沖區滿后數據會經由緩沖輸出流BufferedOutputStream對象流入文件輸出流FileOutputStream對象,并最終輸出到IO文件中去,如果緩沖區不滿的話是不會自發輸出到緩沖輸出流中去的,因此往往我們需要在最后緩沖區不滿的情況下強制執行輸出流的flush方法讓緩沖區數據強制輸出到輸出流中去。這個過程完成了IO文件數據的流轉,中間有一個緩沖區在暫存數據。
public class FilesTest { public byte[] generateString() { StringBuffer buffer = new StringBuffer(); String content = "abcdefg "; for (int i = 0; i < 10000; i++) { buffer.append(content); } return buffer.toString().getBytes(); } public static void main(String[] args) throws IOException { FilesTest filesTest = new FilesTest(); byte[] buffer = filesTest.generateString(); InputStream inputStream = new ByteArrayInputStream(buffer); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); DataInputStream dataInputStream = new DataInputStream(inputStream); bufferedReader.readLine(); System.out.println(dataInputStream.readline()); } }
在這個例子里我們可以更容易地發現BufferedReader這樣的緩沖類輸入流的緩沖作用,當首次調用readline(或者read等各種讀取方法)函數讀取這個輸入流的時候,就會將流里的數據讀進程序為BufferedInputStream對象分配的一個緩沖區中,而在此后的讀取輸入流的過程中就不需要去流中讀取而只需要去緩沖區里讀取就可以了,將開銷較大的IO數據交換過程變成了開銷小得多的內存數據交換,進而提高了IO效率,這是緩沖輸入輸出流的好處。但是這個緩沖區的大小是有限的,jdk為這個大小確定的固定值為8K字節,一旦超過這個值的話在第一次讀取時就只能緩沖最多8K子節的數據,超出的部分只能在之后再緩沖。最后,如果要結束任務寫入輸出流的時候,要注意調用輸出流的flush方法來將緩沖區強制清空使之全部輸出到輸出流中去。
public class FilesTest { public static void main(String[] args) throws IOException { //buffer:8192 File src = new File("1.txt"); File des = new File("2.txt"); FileWriter writer = new FileWriter(src); StringBuffer buffer = new StringBuffer(); for(int i = 0;i<8193;i++){ buffer.append("a"); } writer.write(buffer.toString()); writer.flush(); BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(src)); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(des)); byte[] eachBuffer = new byte[1024]; int haveRead; while((haveRead = bufferedInputStream.read(eachBuffer))!=-1){ bufferedOutputStream.write(eachBuffer); } //bufferedOutputStream.flush(); } }
上面這個過程演示了緩沖區的大小,當輸入流的內容填不滿緩沖區時(也就是不足8192字節時),如果不用flush沒有辦法自動寫入文件,當原來緩沖區的大小大于這個值的時候,會一次性把上次的8192字節自動寫入,下一次會再讀入8192個字節,完成上面的過程。因此,這提醒我們,使用帶有緩沖的輸出流時務必要在最后強制清空緩沖進入輸出流才能保證數據不出錯。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/64622.html
摘要:知識點總結轉換流知識點總結是的子類,將一個字符流的輸出對象變為字節流的輸出對象。將字節輸出流轉為字符輸出流字節流轉為字符流蘋果將字節輸入流轉為字符輸入流內容是 Java知識點總結(JavaIO-轉換流) @(Java知識點總結)[Java, JavaIO] [toc] showImg(https://segmentfault.com/img/bV82dQ?w=849&h=226); O...
摘要:知識點總結字節流知識點總結字節流在程序中所有的數據都是以流的方式進行傳輸或保存的,程序需要數據時要使用輸入流讀取數據,而當程序需要將一些數據保存起來時,就要使用輸出流。字節流主要操作類型數據,以數組為準,主要操作類是類和類。 Java知識點總結(JavaIO-字節流) @(Java知識點總結)[Java, JavaIO] [toc] 字節流 在程序中所有的數據都是以流的方式進行傳輸或保...
摘要:知識點總結內存操作流知識點總結前面所講的程序中輸入輸出都是從文件中來,當然也可以將輸出的位置設置在內存上。將內容寫入到內存中。 Java知識點總結(JavaIO-內存操作流) @(Java知識點總結)[Java, JavaIO] [toc] showImg(https://segmentfault.com/img/bV82tm?w=753&h=275); 前面所講的程序中輸入、輸出都是...
摘要:使用字節流寫入文件,如果沒有關閉字節流操作,文件依然存在內容,說明字節流是操作文件本身的。字節流比字符流更好,使用更廣泛。 Java知識點總結(JavaIO-字符流) @(Java知識點總結)[Java, JavaIO] [toc] 在程序中一個字符等于兩個字節,那么 Java 提供了 Reader 和 Writer 兩個專門操作字符流的類。 字符輸出流:Writer 類定義如下: p...
摘要:知識點總結管道流知識點總結管道流的主要作用是可以進行兩個線程間的通信。如果要進行管道輸出,則必須把輸出流連接在輸入流上,在類上有如下方法用于連接管道。 Java知識點總結(JavaIO-管道流) @(Java知識點總結)[Java, JavaIO] [toc] 管道流的主要作用是可以進行兩個線程間的通信。 如果要進行管道輸出,則必須把輸出流連接在輸入流上,在PipeOutputSt...
閱讀 661·2021-11-15 11:39
閱讀 2898·2021-10-08 10:04
閱讀 3261·2019-08-30 10:57
閱讀 3023·2019-08-26 13:25
閱讀 1904·2019-08-26 12:14
閱讀 2635·2019-08-23 15:27
閱讀 2992·2019-08-23 15:18
閱讀 1774·2019-08-23 14:26