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