java中什么方法用来清空流_这个真的写的很细,JavaIO中的常用处理流,看完只有10%的人还不懂了...
JavaIO中的常用處理流
在前面,我們了解了有關JavaIO流基礎的使用,其中對于IO流來說最基礎的四大基類就是InputStream、OutputStream、Reader、Writer。而我們對文件操作的最常用的子類就是FileInputStream、FileOutputStream、FileReader、FileWriter四大類,他們的用法基本上是完全一樣的,只不過前兩個是操作字節的,后兩個是操作字符的。
字節流和字符流的區別
1、首先操作單元不同。字節流操作的單元是數據單元是8位的字節,字符流操作的是數據單元為16位的字節。
2、其次實際上字節流在操作時本身不會用到緩沖區(內存),是文件本身直接操作的,而字符流在操作時使用了緩沖區,通過緩沖區再操作文件。
緩沖區
緩沖區可以簡單地把緩沖區理解為一段特殊的內存。它的主要作用是:
1、某些情況下,如果一個程序頻繁地操作一個資源(如文件或數據庫),則性能會很低,此時為了提升性能,就可以將一部分數據暫時讀入到內存的一塊區域之中,以后直接從此區域中讀取數據即可,因為讀取內存速度會比較快,這樣可以提升程序的性能。
2、在字符流的操作中,所有的字符都是在內存中形成的,在輸出前會將所有的內容暫時保存在內存之中,所以使用了緩沖區暫存數據。如果想在不關閉時也可以將字符流的內容全部輸出,則可以使用Writer類中的flush()方法完成。
字節流和字符流的使用
開發中究竟用字節流好還是用字符流好呢?
在所有的硬盤上保存文件或進行傳輸的時候都是以字節的方法進行的,包括圖片也是按字節完成,而字符是只有在內存中才會形成的,所以使用字節的操作是最多的。
具體哪個好要是具體環境而定。比如我們要將字符類文件的內容讀取出來對立面的內容進行操作那么這個時候選用字符流更為合適。如果不需要對內容進行操作只是單純的文件傳輸例如文件拷貝那么選用字節流更合適。
FileReader和FileWriter類說明
public class FileReader
public class FileReader
extends InputStreamReader
extends Reader
extends java.lang.Object
FileReader不是Reader的子類,而是轉換流的子類。
public class FileWriter
extends OutputStreamWriter
extends Writer
extends java.lang.Object
FilWriter不是Writer的子類,而是轉換流的子類。
也就是說,不管如何,雖然是以字符的輸出流形式,操作字節流輸出流,但是實際上還是以字節的形式輸出。而字符的輸入流雖然是以字符的形式操作,但是還是使用了字節流,也就是說,在傳輸或者從文件讀取數據的時候,文件里真正保存的數據永遠是字節。
帶Buffered的處理流
BufferedInputStream / BufferedOutputStream 和 BufferedReader / BufferedWriter
這些處理流都是內置一個緩沖區(大小為8kb)。前者處理字節流,后者處理字符流。
常用方法
從流里面讀取文本,通過緩存的方式提高效率,讀取的內容包括字符、數組和行。
緩存的大小可以指定,也可以用默認的大小。大部分情況下,默認大小就夠了。
需要注意的是這里提供了mark和reset功能,也就是可以記住讀取的位置,將來可以回滾,重新讀取。這需要在讀取數據時避免對緩沖區中的這部分數據覆蓋掉,需要保存起來,同時保存的長度可以在mark的時候指定。調用reset可以回滾,但是必須mark過,而且mark過后讀取的數據不能超過mark的時候設置的大小,否則會失效,調用reset會拋出異常。
public class Buffer_Test {
public static void main(String[] args) {
// BufferedOutputStream 和 FileIOutputStream 用法完全一致
//這兩個處理流直接操作的是緩沖區
BufferedOutputStream out;
BufferedInputStream in = null; //輸入流 用法和fileInputStream完全一致
try {
in = new BufferedInputStream(new FileInputStream("D:\\Java文件IO\\Test\\a.txt"));
//參數:字節流必須上輸入流 第二個參數可以指定緩沖區大小 單位是字節
for (int i = 0; i < 1024 * 9; i++) {
in.read(); //只有第一次會從文件中讀8K放入緩沖區,
// 之后就直接從緩沖區中讀取 不用進行文件IO
//直到將緩沖區當中數據讀完 再次讀取8K數據刷新原有的緩沖區
}
out = new BufferedOutputStream(new FileOutputStream( //節點流是直接操作數據的
"D:\\Java文件IO\\Test\\a.txt", true));
out.write(23); //會將寫的數據先存入緩沖區 讓然后攢夠8K 一次性寫入文件
//寫入之后將緩沖區清空(實際上是將下標重新移動到初始位置,會將原數據覆蓋) 繼續接收新數據
//寫的時候要注意 調用flush 方法 和 close方法可以刷新緩沖區
//或者是你寫入的數據數量大于了緩沖區的大小可以不調用這兩個方法
out.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
read()方法的執行過程是:直接從源文件讀取8192字節大小(或者字符大小)的數據,每當我們進行讀取時,就直接從 buf 也就是緩存中去讀寫,如果讀取的內容的大小已經大于了buf的長度,那么 buf 直接返回內存中指定需要的數據(內存大小8192,如果4096的內容已經都去了,這一次要讀取8192,那么直接將剩余的4096字節的內容讀取,再對磁盤進行交互),然后再讀取源文件8192大小,返回給buf緩存,再返回給read(),直到滿足需求。
write()方法,同樣,先把數據寫入緩存,當調用write()方法時,直接從緩存中去寫入,如果寫入的大小大于了 buf 的大小,那么直接flush(),再去將內存更新,再寫入。
read 方法和 write 方法一樣。本質上提升了效率,減少了磁盤的交互。
存在意義
為什么需要帶Buffered處理流?
為了提高字符讀取的效率。
BufferedInputStream和BufferedOutputStream這兩個類分別是FilterInputStream和FilterOutputStream的子類,作為裝飾器子類。并且構造函數需要FilterInputStream/FilterOutputStream的子類入參。
BufferedReader和BufferedWriter這兩個類分別是Reader和Writer的子類,作為裝飾器子類。并且構造函數需要Reader/Writer的子類入參。
使用它們可以防止每次讀取/發送數據時進行實際的寫操作,代表著使用緩沖區。我們有必要知道不帶緩沖的操作,每讀一個字節就要寫入一個字節,由于涉及磁盤的IO操作相比內存的操作要慢很多,所以不帶緩沖的流效率很低。帶緩沖的流,可以一次讀很多字節,但不向磁盤中寫入,只是先放到內存里。等湊夠了緩沖區大小的時候一次性寫入磁盤,這種方式可以減少磁盤操作次數,速度就會提高很多!
也就是說如果當前緩沖區沒有數據,則調用底層reader去讀取數據到緩沖區;如果有數據則直接讀取。默認的 緩沖大小是8k,也就是每次讀取都是8k為單位。
BufferedReader中還提供了一行一行讀取的功能readLine函數,這不是Reader中的方法,這種方法可以把換行符(\r、\n、\r\n)去掉。
flush的作用
BufferedOutputStream在close()時會自動flush,BufferedOutputStream或者Bufferedwriter在不調用close()的情況下,緩沖區不滿,又需要把緩沖區的內容寫入到文件或通過網絡發送到別的機器時,才需要調用flush。
源碼分析
以BufferedInputStream為例:源碼分析
要想讀懂BufferedInputStream的源碼,就要先理解它的思想。
BufferedInputStream的作用是為其它輸入流提供緩沖功能。創建BufferedInputStream時,我們會通過它的構造函數指定某個輸入流為參數。BufferedInputStream會將該輸入流數據分批讀取,每次讀取一部分到緩沖中;操作完緩沖中的這部分數據之后,再從輸入流中讀取下一部分的數據。
為什么需要緩沖呢?
原因很簡單,效率問題!緩沖中的數據實際上是保存在內存中,而原始數據可能是保存在硬盤或NandFlash等存儲介質中;而我們知道,從內存中讀取數據的速度比從硬盤讀取數據的速度至少快10倍以上。
那干嘛不干脆一次性將全部數據都讀取到緩沖中呢?
第一,讀取全部的數據所需要的時間可能會很長。
第二,內存價格很貴,容量不像硬盤那么大。
額外知識
1、類自帶的緩沖區,與我們自己創建的緩沖區有什么不同?
2、既然FileWriter和Filereader中已經帶有緩沖區,還要有BufferReader和BufferWriteer?
Java 在IO操作中,都會有一個緩沖區的,它們不同在于緩沖區的大小。BufferWriter更合理的使用緩沖區,在處理大量的數據時,FileWrite的效率明顯不如BufferWriter。
帶Object的處理流
帶Object的處理流被稱為對象處理流,常見的有兩種:ObjectInputStream和ObjectOutputStream
對象流可以將一個對象寫出,或者讀取一個對象到程序中(對象持久化),也就是執行了序列化和反序列化的操作。
序列化的概念
將一個對象存放到某種類型的永久存儲器上稱為保持。如果一個對象可以被存放到磁盤或磁帶上,或者可以發送到另外一臺機器并存放到存儲器或磁盤上,那么這個對象就被稱為可保持的。
在Java中,序列化、持久化、串行化是一個概念。
參考鏈接:序列化與反序列化
基本使用方法
class Dog implements Serializable {
private static final long serialVersionUID = -5156631308412187014L;
private String name;
private int age;
public Dog() {
}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
//省略get/set方法
}
public class ObjectStreamTest { //對象持久化的過程 數據落地
public static void main(String[] args) {
Dog dog = new Dog("nickel", 8);
//把對象變成字節存儲到文件中
ObjectOutputStream out = null;
ObjectInputStream in = null;
try {
out = new ObjectOutputStream(
new FileOutputStream("D:\\Java\\IoTest\\dog.txt"));
out.writeObject(dog);
System.out.println("---------------反序列化的結果如下-------------------");
in = new ObjectInputStream(
new FileInputStream("D:\\Java\\IoTest\\dog.txt"));
Dog dog1 = (Dog) in.readObject();
System.out.println(dog1);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
注意:我們的對象類一定要實現 Serializable 接口(java.io.Serializable接口沒有任何方法,它只作為一個“標記者”,用來表明實現了這個接口的類可以考慮串行化。類中沒有實現Serializable的對象不能保存或恢復它們的狀態) 不然程序就會報錯。
帶Data的處理類
DataInputStream和DataOutputStream類創建的對象稱為數據輸入流和數據輸出流。它們運行程序按著機器無關的風格讀取Java原始數據。也就是說,當讀取一個數值時,不必再關心這個數值應當是多少個字節。
常用方法
基本使用方法
public class Data_StreamTest {
public static void main(String[] args) {
DataOutputStream out = null;
DataInputStream in = null;
People p = new People("張三", 13, new A(1, "dsad"));
try {
out = new DataOutputStream(new FileOutputStream("D:\\Java\\IoTest\\p.txt"));
out.writeUTF(p.getName());
out.writeInt(p.getAge());
out.writeInt(p.getA().getSex());
out.writeUTF(p.getA().getName());
in = new DataInputStream(new FileInputStream("D:\\Java\\IoTest\\p.txt"));
People p1 = new People();
p1.setName(in.readUTF());
p1.setAge(in.readInt());
A a = new A();
a.setSex(in.readInt());
a.setName(in.readUTF());
p1.setA(a);
System.out.println(p1);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class People {
private String name;
private int age;
private A a;
public People() {
}
public People(String name, int age, A a) {
this.name = name;
this.age = age;
this.a = a;
}
//省略get/set方法
}
class A{
private int sex;
private String name;
public A() {
}
public A(int sex, String name) {
this.sex = sex;
this.name = name;
}
//省略get/set方法
}
對象流和數據流的區別與聯系
1、Object相當于裝IO流的一個盒子,我們可以把對象比作一個個拼好的積木,IO流就是拼積木的積木塊,那么如果要搬走積木(對象),肯定需要把積木(對象)先拆了,再扔進盒子(Object)里,這就是為什么對象要序列化(Serializable)。
2、當然裝的時候我們可以有兩種裝法一種是全放入(output.writeObject(this))第一種盒子(ObjectInputStream),另一種是分類別 (如:比如將屋頂、地板、這些流里面的) 放入(output.writeUTF(number),output.writeUTF(name),output.writeInt(age)…)第二種盒子(DataInputStream),所以在搬到另一個地方的時候,第一種盒子里我們把混在一起的積木塊倒出((Member)intput.readObject()),第二種盒子則是分塊拿出來({input.readUTF(),input.readUTF(),input.readInt()…})。
3、處理基本類型的時候沒有什么很大的區別,區別是Object的可將一個實現了序列化的類實例寫入輸出流中,ObjectInput可以從輸入流中將ObjectOutput輸出的類實例讀入到一個實例中。DataOutputStream只能處理基本類型。(Object處理的類必須是實現了序列化的類)。
總結
以上是生活随笔為你收集整理的java中什么方法用来清空流_这个真的写的很细,JavaIO中的常用处理流,看完只有10%的人还不懂了...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java编程东西好多记不住_课程总结
- 下一篇: fianl属性 java_在Java中使