第一篇:08 Java當(dāng)中的輸入輸出流的學(xué)習(xí)筆記 基本IO
流的分類:
輸入流(InputStream/Reader),輸出流(OutputStream/Writer)
字節(jié)流(InputStream,OutputStream)字符流(Reader/Writer)
節(jié)點(diǎn)流(InputStream/Reader,OutputStream/Writer),處理流(過濾流)BufferedIO(緩沖),DataInputStream/DataOutputStream(各種數(shù)據(jù)類型), InputStreamReader/OutputStreamWriter(轉(zhuǎn)換流),ByteArrayInputStream/ ByteArrayOutputStream(內(nèi)存數(shù)組流)PipedInputStream/ PipedOutputStream(管道流,線程間通訊)
1.或者OutputStream可以創(chuàng)建一個(gè)文件,但是不能創(chuàng)建一個(gè)文件夾。
2.InputStream(OutputStream)和Reader(Writer)的區(qū)別在于字節(jié)和字符,對(duì)于非標(biāo)準(zhǔn)ASCII
編碼(占用兩個(gè)字節(jié)的字符)字節(jié)流會(huì)出現(xiàn)亂碼。
3.使用bufferedIO是為了readline()方法和write(s),s是一個(gè)字符串。而且
bufferedinPutStream有mark和reset方法。
4.InputStreamReader和OutputStreamWriter可以把字節(jié)流轉(zhuǎn)換為字符流。
InputStreamReader需要和InputStream套接。OutputStreamWriter需要和OutputStream套接。OutputStreamWriter可以寫一個(gè)字符串。還有一個(gè)典型的應(yīng)用就是在于對(duì)于System.in的處理。
InputStreamReaderisr =
newInputStreamReader(System.in);
BufferedReaderbr = newBufferedReader(isr);
System.in是一個(gè)InputStream的子類,需要把它改成InputStreamReader然后使用BufferedReader讀出每行的內(nèi)容。
5.DataInputStream,DataOutputStream是用來對(duì)付原始的數(shù)據(jù)類型,比如int,long,double,float 和UTF。
6.ByteArrayInputStream和ByteArrayOutputStream在內(nèi)存中創(chuàng)建一個(gè)字節(jié)數(shù)組。
import java.io.*;
publicclassTestDataStream {
publicstaticvoid main(String[] args){
ByteArrayOutputStreambaos =
newByteArrayOutputStream();//在內(nèi)存中創(chuàng)建了一個(gè)內(nèi)存字節(jié)數(shù)組,并對(duì)上一個(gè)管道baos DataOutputStream dos =
newDataOutputStream(baos);//使用DataOutputStream是為了使用writeDouble,writeBoolean等方法
try {
dos.writeDouble(Math.random());//在字節(jié)數(shù)組當(dāng)中寫入8個(gè)字節(jié)的double類型的數(shù)字 dos.writeBoolean(true);//在字節(jié)數(shù)組中寫入一個(gè)boolean類型的true,占用1個(gè)字節(jié)
ByteArrayInputStreambais =
newByteArrayInputStream(baos.toByteArray());//bais也對(duì)到由baos對(duì)應(yīng)的內(nèi)存字節(jié)數(shù)組
System.out.println(bais.available());//內(nèi)存數(shù)組當(dāng)中有多少字節(jié)可用(也就是說被寫入了多少個(gè)字節(jié)的內(nèi)容)
DataInputStream dis = newDataInputStream(bais);//使用DataInputStream是為了使用readDouble,readBoolean等方法
System.out.println(dis.readDouble());//先寫進(jìn)去的東西要先讀是隊(duì)列
System.out.println(dis.readBoolean());//后寫進(jìn)去的東西要后讀
dos.close();
dis.close();
} catch(IOException e){
e.printStackTrace();
}
}
}
7.PipedInputStream和PipedOutputStream是管道流,用于線程間的通信。一個(gè)線程的PipedInputStream對(duì)象必須從另一個(gè)線程的PipedOutputStream對(duì)象讀取輸入。要使用管道流,必須同時(shí)構(gòu)造管道輸入流和輸出流。
8.Print流就只有輸出流,沒有輸入流。
Print流不會(huì)拋異常,而且都會(huì)自動(dòng)flush。
System.setOut(ps);//修改系統(tǒng)輸出的位置
9.Object流和序列化問題
將對(duì)象轉(zhuǎn)換為字節(jié)流并保存起來(文件,磁盤,網(wǎng)絡(luò)),這種機(jī)制叫做對(duì)象序列化。并在日后還原這個(gè)對(duì)象,這種機(jī)制叫對(duì)象的反序列化。將一個(gè)對(duì)象保存到永久存儲(chǔ)設(shè)備上稱為持續(xù)性。
使用ObjectOutputStream和ObjectInputStream來專門用來把一個(gè)object寫入或者讀出硬盤上。(常用于游戲存盤?)其做法是把整個(gè)的object寫入磁盤或者讀出。
當(dāng)一個(gè)對(duì)象被序列化時(shí),只保存對(duì)象的非靜態(tài)成員變量,不能保存任何的成員方法和靜態(tài)的成員變量。如果一個(gè)對(duì)象的成員變量是一個(gè)對(duì)象,那么這個(gè)對(duì)象的數(shù)據(jù)成員也會(huì)被保存。
為了把一個(gè)類的對(duì)象寫到硬盤或者網(wǎng)絡(luò),就必須實(shí)現(xiàn)serializable接口或Externalizable接口。區(qū)別是在于和Externalizable(外部化)是接口是抽象方法,必須被實(shí)現(xiàn)。而Serializable(序列化)是一個(gè)標(biāo)示形接口,也就是說,這樣的接口是沒有方法。Java當(dāng)中還有很多這樣的接口。但是我們必須實(shí)現(xiàn)這個(gè)接口,這個(gè)接口的意義是在于讓java編譯器知道這個(gè)該類需要實(shí)現(xiàn)了這個(gè)功能。要注意,如果該類沒有實(shí)現(xiàn)這個(gè)接口,會(huì)拋出一個(gè)NotSerializableException。
有的時(shí)候,一個(gè)可序列化的對(duì)象包含對(duì)某個(gè)不可序列化的對(duì)象的引用,那么整個(gè)序列化操作將會(huì)失敗,并且會(huì)拋出一個(gè)NotSerializableException。為了解決這個(gè)問題,可以將這個(gè)引用標(biāo)記為transient,那么對(duì)象仍然可以序列化。也就是說,transient修飾的成員變量在序列化的時(shí)候,是不給予考慮的,也就是說被transient修飾的內(nèi)容是不會(huì)被保存的。
Externalizable接口當(dāng)中有兩個(gè)抽象方法,必須被實(shí)現(xiàn).
第二篇:JAVA,IO流學(xué)習(xí)總結(jié)
篇一:java之io流學(xué)習(xí)總結(jié) java之io流學(xué)習(xí)總結(jié)
一、什么是流?
流就是字節(jié)序列的抽象概念,能被連續(xù)讀取數(shù)據(jù)的數(shù)據(jù)源和能被連續(xù)寫入數(shù)據(jù)的接收端就是流,流機(jī)制是java及c++中的一個(gè)重要機(jī)制,通過流我們可以自由地控制文件、內(nèi)存、io設(shè)備等數(shù)據(jù)的流向。而io流就是用于處理設(shè)備上的數(shù)據(jù),如:硬盤、內(nèi)存、鍵盤錄入等。io流根據(jù)處理類型的不同可分為字節(jié)流和字符流,根據(jù)流向的不同可分為輸入流和輸出流。
二、字節(jié)流和字符流的區(qū)別:字符流,因?yàn)槲募幋a的不同,就有了對(duì)字符進(jìn)行高效操作的字符流對(duì)象,它的原理就是基于字節(jié)流讀取字節(jié)時(shí)去查了指定的碼表。它和字節(jié)流的區(qū)別有兩點(diǎn):1.在讀取數(shù)據(jù)的時(shí)候,字節(jié)流讀到一個(gè)字節(jié)就返回一個(gè)字節(jié),字符流使用了字節(jié)流讀到一個(gè)或多個(gè)字節(jié)(一個(gè)中文對(duì)應(yīng)的字節(jié)數(shù)是兩個(gè),在utf-8碼表中是3個(gè)字節(jié))時(shí),先去查指定的編碼表,再將查到的字符返回;2.字節(jié)流可以處理所有類型的數(shù)據(jù),如jpg、avi、mp3、wav等等,而字符流只能處理字符數(shù)據(jù)。所以可以根據(jù)處理的文件不同考慮使用字節(jié)流還是字符流,如果是純文本數(shù)據(jù)可以優(yōu)先考慮字符流,否則使用字節(jié)流。
三、io體系,所具備的基本功能就是讀和寫: 1.字符流
|--reader(讀)|--writer(寫)reader |--inputstreamreader |--filereader:用于處理文件的字符讀取流對(duì)象 writer |--outputstreamwriter |--filewriter:用于處理文件的字符寫入流對(duì)象
其實(shí)很容易就可以看出來,io體系中的子類名后綴絕大部分是父類名稱,而前綴則是體現(xiàn)子類特有功能的名稱。reader中常見的方法: |--int read()讀取一個(gè)字符,并返回讀到的這個(gè)字符,讀到流的末尾則返回-1。|--int read(char[])將讀到的字符存入指定的數(shù)組中,返回的是讀到的字符個(gè)數(shù),讀到流的末尾則返回-1。|--close()讀取字符其實(shí)用的是window系統(tǒng)的功能,就希望使用完畢后,進(jìn)行資源的釋放。filereader除了自己的構(gòu)造函數(shù)外沒有特有的方法: |--用于讀取文本文件的流對(duì)象。
|--用于關(guān)聯(lián)文本文件。在讀取流對(duì)象初始化時(shí),必須要指定一個(gè)被讀取的文件,如果該文件不存在則會(huì)發(fā)生filenotfoundexception異常。writer中常見的方法: |--write()將一個(gè)字符寫入到流中。|--write(char[])將一個(gè)字符數(shù)組寫入到流中。|--writer(string)將一個(gè)字符寫入到流中。|--flush()刷新流,將流中的數(shù)據(jù)刷新到目的地中,流還存在。|--close()關(guān)閉資源,在關(guān)閉錢會(huì)先調(diào)用flush(),刷新流中的數(shù)據(jù)到目的地。filewriter,除了自己的構(gòu)造函數(shù)外沒有特有的方法: |--該類的特點(diǎn)
|--用于處理文本文件 |--沒有默認(rèn)的編碼表 |--有臨時(shí)緩沖
|--構(gòu)造函數(shù),在寫入流對(duì)象初始化時(shí),必須要有一個(gè)存儲(chǔ)數(shù)據(jù)的目的地。|--filewriter(string filename),該構(gòu)造器是干什么用的呢? |--調(diào)用系統(tǒng)資源
|--在指定位置創(chuàng)建一個(gè)文件,如果該文件已經(jīng)存在則被覆蓋。
|--filewriter(string filename,boolean append),這構(gòu)造器的作用是當(dāng)傳入的boolean類型的值為true時(shí),會(huì)在指定文件末尾處進(jìn)行數(shù)據(jù)的續(xù)寫。
清單1,將文本數(shù)據(jù)保存到文件中代碼 private static void test1(){filewriter fw=null;//初始化filewriter對(duì)象,指定文件名已經(jīng)存儲(chǔ)路徑 fw=new filewriter(d:/test.txt);fw.write(將字符串寫入流);//將流中的數(shù)據(jù)刷新到目的地,流還在 fw.flush();fw.write(將字符串寫入流);} catch(ioexception e){ e.printstacktrace();}finally{ if(fw!=null){ try {fw.close();} catch(ioexception e1){e1.printstacktrace();}}} } 清單2,讀取一個(gè)已有文本文件,并將文本內(nèi)容打印出來代碼 private static void test2(){filereader fr=null;try { //初始化filereader對(duì)象,指定文件路徑 fr=new filereader(d:/test.txt);int ch=0;while((ch=fr.read())!=-1){ //每次讀取一個(gè)字符,直到讀到末尾-1為止 system.out.println((char)ch);} catch(ioexception e){ e.printstacktrace();}finally{ if(fr!=null){ try {fr.close();} catch(ioexception e1){e1.printstacktrace();}}} } 這樣每讀到一個(gè)字符就打印出來,效率很不高,能不能按指定大小讀取完后再打印出來呢?答案是當(dāng)然可以的。
清單3,讀取一個(gè)已有文本文件,讀完1kb再將其讀到的內(nèi)容打印出來代碼 private static void test3(){filereader fr=null;try { //初始化filereader對(duì)象,指定文件路徑 fr=new filereader(d:/test.txt);char[] buf=new char[1024];int len=0;while((len=fr.read(buf))!=-1){ //每次讀取1kb大小的字符,直到讀到末尾-1為止
system.out.println(new string(buf,0,len));}} catch(ioexception e){篇二:java io流學(xué)習(xí)總結(jié) java流操作有關(guān)的類或接口:
java流類圖結(jié)構(gòu):流的概念和作用
流是一組有順序的,有起點(diǎn)和終點(diǎn)的字節(jié)集合,是對(duì)數(shù)據(jù)傳輸?shù)目偡Q或抽象。即數(shù)據(jù)在兩設(shè)備間的傳輸稱為流,流的本質(zhì)是數(shù)據(jù)傳輸,根據(jù)數(shù)據(jù)傳輸特性將流抽象為各種類,方便更直觀的進(jìn)行數(shù)據(jù)操作。io流的分類
? 根據(jù)處理數(shù)據(jù)類型的不同分為:字符流和字節(jié)流 ? 根據(jù)數(shù)據(jù)流向不同分為:輸入流和輸出流
字符流和字節(jié)流
字符流的由來: 因?yàn)閿?shù)據(jù)編碼的不同,而有了對(duì)字符進(jìn)行高效操作的流對(duì)象。本質(zhì)其實(shí)就是基于字節(jié)流讀取時(shí),去查了指定的碼表。字節(jié)流和字符流的區(qū)別:
? 讀寫單位不同:字節(jié)流以字節(jié)(8bit)為單位,字符流以字符為單位,根據(jù)碼表映射 字符,一次可能讀多個(gè)字節(jié)。
? 處理對(duì)象不同:字節(jié)流能處理所有類型的數(shù)據(jù)(如圖片、avi等),而字符流只能處 理字符類型的數(shù)據(jù)。
結(jié)論:只要是處理純文本數(shù)據(jù),就優(yōu)先考慮使用字符流。除此之外都使用字節(jié)流。輸入流和輸出流
對(duì)輸入流只能進(jìn)行讀操作,對(duì)輸出流只能進(jìn)行寫操作,程序中需要根據(jù)待傳輸數(shù)據(jù)的不同特性而使用不同的流。java io流對(duì)象
1.輸入字節(jié)流inputstreamio 中輸入字節(jié)流的繼承圖可見上圖,可以看出: 1.inputstream 是所有的輸入字節(jié)流的父類,它是一個(gè)抽象類。
2.bytearrayinputstream、stringbufferinputstream、fileinputstream 是三種基本的介質(zhì)
流,它們分別從byte 數(shù)組、stringbuffer、和本地文件中讀取數(shù)據(jù)。pipedinputstream 是從與其它線程共用的管道中讀取數(shù)據(jù),與piped 相關(guān)的知識(shí)后續(xù)單獨(dú)介紹。3.objectinputstream 和所有filterinputstream 的子類都是裝飾流(裝飾器模式的主角)。2.輸出字節(jié)流outputstream io 中輸出字節(jié)流的繼承圖可見上圖,可以看出:
1.outputstream 是所有的輸出字節(jié)流的父類,它是一個(gè)抽象類。2.bytearrayoutputstream、fileoutputstream 是兩種基本的介質(zhì)流,它們分別向byte 數(shù) 組、和本地文件中寫入數(shù)據(jù)。pipedoutputstream 是向與其它線程共用的管道中寫入數(shù)據(jù),3.objectoutputstream 和所有filteroutputstream 的子類都是裝飾流。3.字節(jié)流的輸入與輸出的對(duì)應(yīng)
圖中藍(lán)色的為主要的對(duì)應(yīng)部分,紅色的部分就是不對(duì)應(yīng)部分。紫色的虛線部分代表這些流一般要搭配使用。從上面的圖中可以看出java io 中的字節(jié)流是極其對(duì)稱的?!按嬖诩昂侠怼蔽覀兛纯催@些字節(jié)流中不太對(duì)稱的幾個(gè)類吧!
1.linenumberinputstream 主要完成從流中讀取數(shù)據(jù)時(shí),會(huì)得到相應(yīng)的行號(hào),至于什么 時(shí)候分行、在哪里分行是由改類主動(dòng)確定的,并不是在原始中有這樣一個(gè)行號(hào)。在輸出部分沒有對(duì)應(yīng)的部分,我們完全可以自己建立一個(gè)linenumberoutputstream,在最初寫入時(shí)會(huì)有一個(gè)基準(zhǔn)的行號(hào),以后每次遇到換行時(shí)會(huì)在下一行添加一個(gè)行號(hào),看起來也是可以的。好像更不入流了。
2.pushbackinputstream 的功能是查看最后一個(gè)字節(jié),不滿意就放入緩沖區(qū)。主要用在 編譯器的語法、詞法分析部分。輸出部分的bufferedoutputstream 幾乎實(shí)現(xiàn)相近的功能。3.stringbufferinputstream 已經(jīng)被deprecated,本身就不應(yīng)該出現(xiàn)在inputstream 部分,主要因?yàn)閟tring 應(yīng)該屬于字符流的范圍。已經(jīng)被廢棄了,當(dāng)然輸出部分也沒有必要需要它了!還允許它存在只是為了保持版本的向下兼容而已。
4.sequenceinputstream 可以認(rèn)為是一個(gè)工具類,將兩個(gè)或者多個(gè)輸入流當(dāng)成一個(gè)輸入 流依次讀取。完全可以從io 包中去除,還完全不影響io 包的結(jié)構(gòu),卻讓其更“純潔”――純潔的decorator 模式。
5.printstream 也可以認(rèn)為是一個(gè)輔助工具。主要可以向其他輸出流,或者
fileinputstream 寫入數(shù)據(jù),本身內(nèi)部實(shí)現(xiàn)還是帶緩沖的。本質(zhì)上是對(duì)其它流的綜合運(yùn)用的一個(gè)工具而已。一樣可以踢出io 包!system.out 和system.out 就是printstream 的實(shí)例!4.字符輸入流reader在上面的繼承關(guān)系圖中可以看出: 1.reader 是所有的輸入字符流的父類,它是一個(gè)抽象類。
2.charreader、stringreader 是兩種基本的介質(zhì)流,它們分別將char 數(shù)組、string中 讀取數(shù)據(jù)。pipedreader 是從與其它線程共用的管道中讀取數(shù)據(jù)。
3.bufferedreader 很明顯就是一個(gè)裝飾器,它和其子類負(fù)責(zé)裝飾其它reader 對(duì)象。4.filterreader 是所有自定義具體裝飾流的父類,其子類pushbackreader 對(duì)reader 對(duì) 象進(jìn)行裝飾,會(huì)增加一個(gè)行號(hào)。
5.inputstreamreader 是一個(gè)連接字節(jié)流和字符流的橋梁,它將字節(jié)流轉(zhuǎn)變?yōu)樽址?。filereader 可以說是一個(gè)達(dá)到此功能、常用的工具類,在其源代碼中明顯使用了將fileinputstream 轉(zhuǎn)變?yōu)閞eader 的方法。我們可以從這個(gè)類中得到一定的技巧。reader 中各個(gè)類的用途和使用方法基本和inputstream 中的類使用一致。后面會(huì)有reader 與inputstream 的對(duì)應(yīng)關(guān)系。5.字符輸出流writer 在上面的關(guān)系圖中可以看出:
1.writer 是所有的輸出字符流的父類,它是一個(gè)抽象類。2.chararraywriter、stringwriter 是兩種基本的介質(zhì)流,它們分別向char 數(shù)組、string 中寫入數(shù)據(jù)。pipedwriter 是向與其它線程共用的管道中寫入數(shù)據(jù),3.bufferedwriter 是一個(gè)裝飾器為writer 提供緩沖功能。
4.printwriter 和printstream 極其類似,功能和使用也非常相似。5.outputstreamwriter 是outputstream 到writer 轉(zhuǎn)換的橋梁,它的子類filewriter 其 實(shí)就是一個(gè)實(shí)現(xiàn)此功能的具體類(具體可以研究一sourcecode)。功能和使用和outputstream 極其類似,后面會(huì)有它們的對(duì)應(yīng)圖。6.字符流的輸入與輸出的對(duì)應(yīng) 7.字符流與字節(jié)流轉(zhuǎn)換 轉(zhuǎn)換流的特點(diǎn):
1.其是字符流和字節(jié)流之間的橋梁
2.可對(duì)讀取到的字節(jié)數(shù)據(jù)經(jīng)過指定編碼轉(zhuǎn)換成字符 3.可對(duì)讀取到的字符數(shù)據(jù)經(jīng)過指定編碼轉(zhuǎn)換成字節(jié) 何時(shí)使用轉(zhuǎn)換流?
1.當(dāng)字節(jié)和字符之間有轉(zhuǎn)換動(dòng)作時(shí); 2.流操作的數(shù)據(jù)需要編碼或解碼時(shí)。具體的對(duì)象體現(xiàn):
1.inputstreamreader:字節(jié)到字符的橋梁 2.outputstreamwriter:字符到字節(jié)的橋梁
這兩個(gè)流對(duì)象是字符體系中的成員,它們有轉(zhuǎn)換作用,本身又是字符流,所以在構(gòu)造的時(shí)候需要傳入字節(jié)流對(duì)象進(jìn)來。8.file類
file類是對(duì)文件系統(tǒng)中文件以及文件夾進(jìn)行封裝的對(duì)象,可以通過對(duì)象的思想來操作文件和文件夾。file類保存文件或目錄的各種元數(shù)據(jù)信息,包括文件名、文件長(zhǎng)度、最后修改時(shí)間、是否可讀、獲取當(dāng)前文件的路徑名,判斷指定文件是否存在、獲得當(dāng)前目錄中的文件列表,創(chuàng)建、刪除文件和目錄等方法。篇三:java io流學(xué)習(xí)總結(jié) java流操作有關(guān)的類或接口:
java流類圖結(jié)構(gòu):流的概念和作用
流是一組有順序的,有起點(diǎn)和終點(diǎn)的字節(jié)集合,是對(duì)數(shù)據(jù)傳輸?shù)目偡Q或抽象。即數(shù)據(jù)在兩設(shè)備間的傳輸稱為流,流的本質(zhì)是數(shù)據(jù)傳輸,根據(jù)數(shù)據(jù)傳輸特性將流抽象為各種類,方便更直觀的進(jìn)行數(shù)據(jù)操作。io流的分類
根據(jù)處理數(shù)據(jù)類型的不同分為:字符流和字節(jié)流 ? 根據(jù)數(shù)據(jù)流向不同分為:輸入流和輸出流 ? 字符流和字節(jié)流
字符流的由來: 因?yàn)閿?shù)據(jù)編碼的不同,而有了對(duì)字符進(jìn)行高效操作的流對(duì)象。本質(zhì)其實(shí)就是基于字節(jié)流讀取時(shí),去查了指定的碼表。字節(jié)流和字符流的區(qū)別:
讀寫單位不同:字節(jié)流以字節(jié)(8bit)為單位,字符流以字符為單位,根據(jù)碼表映射字符,一次可能讀多個(gè)字節(jié)。
? 處理對(duì)象不同:字節(jié)流能處理所有類型的數(shù)據(jù)(如圖片、avi等),而字符流只能處理字符類型的數(shù)據(jù)。? 結(jié)論:只要是處理純文本數(shù)據(jù),就優(yōu)先考慮使用字符流。除此之外都使用字節(jié)流。
輸入流和輸出流
對(duì)輸入流只能進(jìn)行讀操作,對(duì)輸出流只能進(jìn)行寫操作,程序中需要根據(jù)待傳輸數(shù)據(jù)的不同特性而使用不同的流。java io流對(duì)象
1.輸入字節(jié)流inputstreamio 中輸入字節(jié)流的繼承圖可見上圖,可以看出: 1.inputstream 是所有的輸入字節(jié)流的父類,它是一個(gè)抽象類。
2.bytearrayinputstream、stringbufferinputstream、fileinputstream 是三種基本的介質(zhì)流,它們分別從byte 數(shù)組、stringbuffer、和本地文件中讀取數(shù)據(jù)。pipedinputstream 是從與其它線程共用的管道中讀取數(shù)據(jù),與piped 相關(guān)的知識(shí)后續(xù)單獨(dú)介紹。3.objectinputstream 和所有filterinputstream 的子類都是裝飾流(裝飾器模式的主角)。2.輸出字節(jié)流outputstream io 中輸出字節(jié)流的繼承圖可見上圖,可以看出:
1.outputstream 是所有的輸出字節(jié)流的父類,它是一個(gè)抽象類。2.bytearrayoutputstream、fileoutputstream 是兩種基本的介質(zhì)流,它們分別向byte 數(shù)組、和本地文件中寫入數(shù)據(jù)。pipedoutputstream 是向與其它線程共用的管道中寫入數(shù)據(jù),3.objectoutputstream 和所有filteroutputstream 的子類都是裝飾流。3.字節(jié)流的輸入與輸出的對(duì)應(yīng)
圖中藍(lán)色的為主要的對(duì)應(yīng)部分,紅色的部分就是不對(duì)應(yīng)部分。紫色的虛線部分代表這些流一般要搭配使用。從上面的圖中可以看出java io 中的字節(jié)流是極其對(duì)稱的。“存在及合理”我們看看這些字節(jié)流中不太對(duì)稱的幾個(gè)類吧!1.linenumberinputstream 主要完成從流中讀取數(shù)據(jù)時(shí),會(huì)得到相應(yīng)的行號(hào),至于什么時(shí)候分行、在哪里分行是由改類主動(dòng)確定的,并不是在原始中有這樣一個(gè)行號(hào)。在輸出部分沒有對(duì)應(yīng)的部 分,我們完全可以自己建立一個(gè)linenumberoutputstream,在最初寫入時(shí)會(huì)有一個(gè)基準(zhǔn)的行號(hào),以后每次遇到換行時(shí)會(huì)在下一行添加一個(gè)行 號(hào),看起來也是可以的。好像更不入流了。2.pushbackinputstream 的功能是查看最后一個(gè)字節(jié),不滿意就放入緩沖區(qū)。主要用在編譯器的語法、詞法分析部分。輸出部分的
bufferedoutputstream 幾乎實(shí)現(xiàn)相近的功能。3.stringbufferinputstream 已經(jīng)被deprecated,本身就不應(yīng)該出現(xiàn)在inputstream 部分,主要因?yàn)閟tring 應(yīng)該屬于字符流的范圍。已經(jīng)被廢棄了,當(dāng)然輸出部分也沒有必要需要它了!還允許它存在只是為了保持版本的向下兼容而已。4.sequenceinputstream 可以認(rèn)為是一個(gè)工具類,將兩個(gè)或者多個(gè)輸入流當(dāng)成一個(gè)輸入流依次讀取。完全可以從io 包中去除,還完全不影響io 包的結(jié)構(gòu),卻讓其更“純潔”――純潔的decorator 模式。5.printstream 也可以認(rèn)為是一個(gè)輔助工具。主要可以向其他輸出流,或者fileinputstream 寫入數(shù)據(jù),本身內(nèi)部實(shí)現(xiàn)還是帶緩沖的。本質(zhì)上是對(duì)其它流的綜合運(yùn)用的一個(gè)工具而已。一樣可以踢出io 包!system.out 和system.out 就是printstream 的實(shí)例!4.字符輸入流reader 在上面的繼承關(guān)系圖中可以看出:
1.reader 是所有的輸入字符流的父類,它是一個(gè)抽象類。
2.charreader、stringreader 是兩種基本的介質(zhì)流,它們分別將char 數(shù)組、string中讀取數(shù)據(jù)。pipedreader 是從與其它線程共用的管道中讀取數(shù)據(jù)。
3.bufferedreader 很明顯就是一個(gè)裝飾器,它和其子類負(fù)責(zé)裝飾其它reader 對(duì)象。4.filterreader 是所有自定義具體裝飾流的父類,其子類pushbackreader 對(duì)reader 對(duì)象進(jìn)行裝飾,會(huì)增加一個(gè)行號(hào)。
5.inputstreamreader 是一個(gè)連接字節(jié)流和字符流的橋梁,它將字節(jié)流轉(zhuǎn)變?yōu)樽址鳌ilereader 可以說是一個(gè)達(dá)到此功能、常用的工具類,在其源代碼中明顯使用了將fileinputstream 轉(zhuǎn)變?yōu)閞eader 的方法。我們可以從這個(gè)類中得到一定的技巧。reader 中各個(gè)類的用途和使用方法基本和inputstream 中的類使用一致。后面會(huì)有reader 與inputstream 的對(duì)應(yīng)關(guān)系。5.字符輸出流writer 在上面的關(guān)系圖中可以看出:
1.writer 是所有的輸出字符流的父類,它是一個(gè)抽象類。2.chararraywriter、stringwriter 是兩種基本的介質(zhì)流,它們分別向char 數(shù)組、string 中寫入數(shù)據(jù)。pipedwriter 是向與其它線程共用的管道中寫入數(shù)據(jù),3.bufferedwriter 是一個(gè)裝飾器為writer 提供緩沖功能。
4.printwriter 和printstream 極其類似,功能和使用也非常相似。5.outputstreamwriter 是outputstream 到writer 轉(zhuǎn)換的橋梁,它的子類filewriter 其實(shí)就是一個(gè)實(shí)現(xiàn)此功能的具體類(具體可以研究一 sourcecode)。功能和使用和outputstream 極其類似,后面會(huì)有它們的對(duì)應(yīng)圖。
第三篇:Java之IO流學(xué)習(xí)總結(jié)
Java之IO流學(xué)習(xí)總結(jié)
一、什么是流?
流就是字節(jié)序列的抽象概念,能被連續(xù)讀取數(shù)據(jù)的數(shù)據(jù)源和能被連續(xù)寫入數(shù)據(jù)的接收端就是流,流機(jī)制是Java及C++中的一個(gè)重要機(jī)制,通過流我們可以自由地控制文件、內(nèi)存、IO設(shè)備等數(shù)據(jù)的流向。而IO流就是用于處理設(shè)備上的數(shù)據(jù),如:硬盤、內(nèi)存、鍵盤錄入等。IO流根據(jù)處理類型的不同可分為字節(jié)流和字符流,根據(jù)流向的不同可分為輸入流和輸出流。
字符流,因?yàn)槲募幋a的不同,就有了對(duì)字符進(jìn)行高效操作的字符流對(duì)象,它的原理就是基于字節(jié)流讀取字節(jié)時(shí)去查了指定的碼表。它和字節(jié)流的區(qū)別有兩點(diǎn):1.在讀取數(shù)據(jù)的時(shí)候,字節(jié)流讀到一個(gè)字節(jié)就返回一個(gè)字節(jié),字符流使用了字節(jié)流讀到一個(gè)或多個(gè)字節(jié)(一個(gè)中文對(duì)應(yīng)的字節(jié)數(shù)是兩個(gè),在UTF-8碼表中是3個(gè)字節(jié))時(shí),先去查指定的編碼表,再將查到的字符返回;2.字節(jié)流可以處理所有類型的數(shù)據(jù),如jpg、avi、mp3、wav等等,而字符流只能處理字符數(shù)據(jù)。所以可以根據(jù)處理的文件不同考慮使用字節(jié)流還是字符流,如果是純文本數(shù)據(jù)可以優(yōu)先考慮字符流,否則使用字節(jié)流。
三、IO體系,所具備的基本功能就是讀和寫: 1.字符流
|--Reader(讀)|--Writer(寫)Reader
|--InputStreamReader
|--FileReader:用于處理文件的字符讀取流對(duì)象 Writer
|--OutputStreamWriter
|--FileWriter:用于處理文件的字符寫入流對(duì)象
其實(shí)很容易就可以看出來,IO體系中的子類名后綴絕大部分是父類名稱,而前綴則是體現(xiàn)子類特有功能的名稱。Reader中常見的方法: |--int read()
讀取一個(gè)字符,并返回讀到的這個(gè)字符,讀到流的末尾則返回-1。|--int read(char[])
將讀到的字符存入指定的數(shù)組中,返回的是讀到的字符個(gè)數(shù),讀到流的末尾則返回-1。|--close()
讀取字符其實(shí)用的是window系統(tǒng)的功能,就希望使用完畢后,進(jìn)行資源的釋放。FileReader除了自己的構(gòu)造函數(shù)外沒有特有的方法: |--用于讀取文本文件的流對(duì)象。|--用于關(guān)聯(lián)文本文件。
|--構(gòu)造函數(shù)FileReader(String fileName)在讀取流對(duì)象初始化時(shí),必須要指定一個(gè)被讀取的文件,如果該文件不存在則會(huì)發(fā)生FileNotFoundException異常。Writer中常見的方法: |--write()
將一個(gè)字符寫入到流中。|--write(char[])
將一個(gè)字符數(shù)組寫入到流中。|--writer(String)將一個(gè)字符寫入到流中。|--flush()
刷新流,將流中的數(shù)據(jù)刷新到目的地中,流還存在。|--close()
關(guān)閉資源,在關(guān)閉錢會(huì)先調(diào)用flush(),刷新流中的數(shù)據(jù)到目的地。
FileWriter,除了自己的構(gòu)造函數(shù)外沒有特有的方法:
|--該類的特點(diǎn) |--用于處理文本文件 |--沒有默認(rèn)的編碼表 |--有臨時(shí)緩沖
|--構(gòu)造函數(shù),在寫入流對(duì)象初始化時(shí),必須要有一個(gè)存儲(chǔ)數(shù)據(jù)的目的地。|--FileWriter(String fileName),該構(gòu)造器是干什么用的呢? |--調(diào)用系統(tǒng)資源
|--在指定位置創(chuàng)建一個(gè)文件,如果該文件已經(jīng)存在則被覆蓋。
|--FileWriter(String filename,Boolean append),這構(gòu)造器的作用是當(dāng)傳入的boolean類型的值為true時(shí),會(huì)在指定文件末尾處進(jìn)行數(shù)據(jù)的續(xù)寫。
清單1,將文本數(shù)據(jù)保存到文件中代碼 private static void test1(){ FileWriter fw=null;try { //初始化FileWriter對(duì)象,指定文件名已經(jīng)存儲(chǔ)路徑 fw=new FileWriter(“D:/test.txt”);fw.write(“將字符串寫入流”);//將流中的數(shù)據(jù)刷新到目的地,流還在 fw.flush();fw.write(“將字符串寫入流”);} catch(IOException e){ e.printStackTrace();}finally{ if(fw!=null){ try { fw.close();} catch(IOException e1){ e1.printStackTrace();} } } }
清單2,讀取一個(gè)已有文本文件,并將文本內(nèi)容打印出來代碼 private static void test2(){ FileReader fr=null;try { //初始化FileReader對(duì)象,指定文件路徑 fr=new FileReader(“D:/test.txt”);int ch=0;while((ch=fr.read())!=-1){ //每次讀取一個(gè)字符,直到讀到末尾-1為止 System.out.println((char)ch);} } catch(IOException e){ e.printStackTrace();}finally{ if(fr!=null){ try { fr.close();} catch(IOException e1){ e1.printStackTrace();} } } }
這樣每讀到一個(gè)字符就打印出來,效率很不高,能不能按指定大小讀取完后再打印出來呢?答案是當(dāng)然可以的。
清單3,讀取一個(gè)已有文本文件,讀完1kb再將其讀到的內(nèi)容打印出來代碼 private static void test3(){ FileReader fr=null;try { //初始化FileReader對(duì)象,指定文件路徑 fr=new FileReader(“D:/test.txt”);char[] buf=new char[1024];int len=0;while((len=fr.read(buf))!=-1){ //每次讀取1kb大小的字符,直到讀到末尾-1為止 System.out.println(new String(buf,0,len));} } catch(IOException e){ e.printStackTrace();}finally{ if(fr!=null){ try { fr.close();} catch(IOException e1){ e1.printStackTrace();} } } }
字符流的緩沖區(qū):
|--緩沖區(qū)的出現(xiàn)提高了對(duì)流的操作效率。原理:其實(shí)就是將數(shù)組進(jìn)行封裝。|--對(duì)應(yīng)的對(duì)象 |--BufferedWriter
特有方法newLine(),跨平臺(tái)的換行符。|--BufferedReader
特有方法readLine(),一次讀一行,到行標(biāo)記時(shí),將行標(biāo)記之前的字符數(shù)據(jù)作為字符串返回,讀到末尾返回null。
|--說明在使用緩沖區(qū)對(duì)象時(shí),要明確,緩沖的存在是為了增強(qiáng)流的功能而存在,所以在建立緩沖區(qū)對(duì)象時(shí),要先有流對(duì)象存在。其實(shí)緩沖區(qū)內(nèi)部就是在使用流對(duì)象的方法,只不過加入了數(shù)組對(duì)數(shù)據(jù)進(jìn)行了臨時(shí)存儲(chǔ),為了提高操作數(shù)據(jù)的效率。
|--代碼上的體現(xiàn) |--寫入緩沖區(qū)對(duì)象
根據(jù)前面所說的建立緩沖區(qū)時(shí)要先有流對(duì)象,并將其作為參數(shù)傳遞給緩沖區(qū)的構(gòu)造函數(shù) BufferedWriter bufw=new BufferedWriter(new FileWriter(“test.txt”));bufw.write(“將數(shù)據(jù)寫入緩沖區(qū)”);
bufw.flush();//將緩沖區(qū)的數(shù)據(jù)刷新到目的地 bufw.close();//其實(shí)關(guān)閉的是被包裝在內(nèi)部的流對(duì)象 |--讀取緩沖區(qū)對(duì)象
BufferedReader bufr=new BufferedReader(new FileReader(“test.txt”));String line=null;
while((line=bufr.readLine())!=null){ //每次讀取一行,取出的數(shù)據(jù)不包含回車符 system.out.println(line);}
bufr.close();
清單4,使用緩沖區(qū)對(duì)文本文件進(jìn)行拷貝代碼 private static void test4(){ BufferedReader bufr=null;BufferedWriter bufw=null;try {
bufr=new BufferedReader(new FileReader(“D:/a.txt”));bufw=new BufferedWriter(new FileWriter(“D:/b.txt”));String line=null;while((line=bufr.readLine())!=null){ bufw.write(line);//每次將一行寫入緩沖區(qū) bufw.flush();//刷新到目的地 } } catch(IOException e){ e.printStackTrace();}finally{ try { if(bufw!=null){ bufw.close();} if(bufr!=null){ bufr.close();} } catch(IOException e1){ e1.printStackTrace();} } }
仔細(xì)看可以發(fā)現(xiàn),程序里面的FileReader對(duì)象和FileWriter對(duì)象直接new出來且沒有調(diào)用close(),因?yàn)榫彌_對(duì)象調(diào)用了這兩個(gè)方法,前面說了,緩沖對(duì)象調(diào)用的flush()和close()其實(shí)就是關(guān)閉被包裝在其內(nèi)部的流對(duì)象。關(guān)閉流的先后順序也要注意,如果流之間有依賴關(guān)系,則被依賴的流要后關(guān)閉。readLine()方法原理:其實(shí)緩沖區(qū)中的該方法,用的還是與緩沖區(qū)關(guān)聯(lián)的流對(duì)象的read方法,只不過,每一次讀到一個(gè)字符先不進(jìn)行具體操作,先進(jìn)行臨時(shí)存儲(chǔ),當(dāng)讀到回車標(biāo)記時(shí),將臨時(shí)容器中存儲(chǔ)的數(shù)據(jù)一次性返回。我們可以根據(jù)這個(gè)原理來自己編寫一個(gè)緩沖區(qū)對(duì)象。
清單5,編寫一個(gè)自己的bufferedreader代碼
public class MyBufferedReader { private Reader reader;public MyBufferedReader(Reader reader){ this.reader=reader;}
public String readLine()throws IOException{ StringBuilder sb=new StringBuilder();int ch=0;while((ch=reader.read())!=-1){ if(ch=='r'){//空格則繼續(xù) continue;}else if(ch=='n'){//每次返回一行 return sb.toString();}else{ sb.append((char)ch);} } return sb.toString();}
public void close()throws IOException{ //緩沖對(duì)象的關(guān)閉方法其實(shí)就是調(diào)用流本身的close()reader.close();} }
測(cè)試時(shí)把清單4的BufferedReader對(duì)象替換成MyBufferedReader對(duì)象即可。
清單6,測(cè)試mybufferedreader代碼 private static void test4(){ MyBufferedReader bufr=null;BufferedWriter bufw=null;try {
bufr=new MyBufferedReader(new FileReader(“D:/a.txt”));bufw=new BufferedWriter(new FileWriter(“D:/b.txt”));String line=null;while((line=bufr.readLine())!=null){ bufw.write(line);//每次將一行寫入緩沖區(qū) bufw.flush();//刷新到目的地 } } catch(IOException e){ e.printStackTrace();}finally{ try { if(bufw!=null){ bufw.close();} if(bufr!=null){ bufr.close();} } catch(IOException e1){ e1.printStackTrace();} } }
其實(shí)我們自己寫的這個(gè)緩存對(duì)象就是對(duì)Reader對(duì)象進(jìn)行了功能的增強(qiáng),Reader對(duì)象每次只能返回一個(gè)字符,而增強(qiáng)了功能之后該類就可以每次返回一行字符,也就是設(shè)計(jì)模式中所說的裝飾模式。
2.字節(jié)流
|--InputStream(讀)|--OutputStream(寫)
由于字節(jié)是二進(jìn)制數(shù)據(jù),所以字節(jié)流可以操作任何類型的數(shù)據(jù),值得注意的是字符流使用的是字符數(shù)組char[]而字節(jié)流使用的是字節(jié)數(shù)組byte[]。下面來看一個(gè)字節(jié)流讀寫文件的簡(jiǎn)單例子。
清單7,使用字節(jié)流讀寫文本文件代碼 private static void test5(){ FileOutputStream fos=null;try{ fos=new FileOutputStream(“D:/test.txt”);fos.write(0010);//寫入二進(jìn)制數(shù)據(jù) fos.flush();}catch(IOException e){ }finally{ try{ fos.close();}catch(IOException ex){ } } FileInputStream fis=null;try{ fis=new FileInputStream(“D:/test.txt”);//fis.available()是獲取關(guān)聯(lián)文件的字節(jié)數(shù),即test.txt的字節(jié)數(shù) //這樣創(chuàng)建的數(shù)組大小就和文件大小剛好相等
//這樣做的缺點(diǎn)就是文件過大時(shí),可能超出jvm的內(nèi)存空間,從而造成內(nèi)存溢出 byte[] buf=new byte[fis.available()];fis.read(buf);System.out.println(new String(buf));}catch(IOException e){ }finally{ try{ fos.close();}catch(IOException ex){ } } }
清單8,使用緩沖區(qū)對(duì)一張圖片進(jìn)行復(fù)制代碼 private static void test6(){ BufferedOutputStream bos=null;BufferedInputStream bis=null;try{ //前面已經(jīng)說過了,緩沖對(duì)象是根據(jù)具體的流對(duì)象創(chuàng)建的,所以必須要有流對(duì)象 bis=new BufferedInputStream(new FileInputStream(“E:imageswo1.jpg”));//寫入目標(biāo)地址
bos=new BufferedOutputStream(new FileOutputStream(“E: est.jpg”));byte[] buf=new byte[1024];while((bis.read(buf))!=-1){ bos.write(buf);} bos.flush();}catch(IOException e){ e.toString();}finally{ try{ if(bos!=null){ bos.close();} if(bis!=null){ bis.close();} }catch(IOException ex){ ex.toString();} } }
3.轉(zhuǎn)換流
特點(diǎn)
|--是字節(jié)流和字符流之間的橋梁
|--該流對(duì)象可以對(duì)讀取到的字節(jié)數(shù)據(jù)進(jìn)行指定編碼表的編碼轉(zhuǎn)換
何時(shí)使用
|--當(dāng)字節(jié)和字符之間有轉(zhuǎn)換動(dòng)作時(shí) |--流操作的數(shù)據(jù)需要進(jìn)行編碼表的指定時(shí)
具體對(duì)象體現(xiàn)
|--InputStreamReader:字節(jié)到字符的橋梁 |--OutputStreamWriter:字符到字節(jié)的橋梁
說明
這兩個(gè)流對(duì)象是字符流體系中的成員,它們有轉(zhuǎn)換的作用,而本身又是字符流,所以在new的時(shí)候需要傳入字節(jié)流對(duì)象。
構(gòu)造函數(shù)
|--InputStreamReader(InputStream)
通過該構(gòu)造函數(shù)初始化,使用的是系統(tǒng)默認(rèn)的編碼表GBK。|--InputStreamReader(InputStream,String charset)
通過該構(gòu)造函數(shù)初始化,可以通過charset參數(shù)指定編碼。|--OutputStreamWriter(OutputStream)
使用的是系統(tǒng)默認(rèn)的編碼表GBK。
|--OutputStreamWriter(OutputSream,String charset)
通過該構(gòu)造函數(shù)初始化,可以通過參數(shù)charset指定編碼。
操作文件的字符流對(duì)象是轉(zhuǎn)換流的子類
|--Reader
|--InputStreamReader(轉(zhuǎn)換流)|--FileReader(文件字符流)
|--Writer
|--OutputStreamWriter(轉(zhuǎn)換流)|--FileWriter(文件字符流)
說明
轉(zhuǎn)換流中的read方法,已經(jīng)融入了編碼表,在底層調(diào)用字節(jié)流的read方法時(shí)將獲取的一個(gè)或者多個(gè)字節(jié)數(shù)據(jù)進(jìn)行臨時(shí)存儲(chǔ),并去查指定的編碼表,如果編碼沒有指定,則使用默認(rèn)編碼表。
既然轉(zhuǎn)換流已經(jīng)完成了編碼轉(zhuǎn)換的動(dòng)作,對(duì)于直接操作的文本文件的FileReader而言,就不用再重新定義了,只要繼承該轉(zhuǎn)換流,獲取其方法,就可以直接操作文本文件中的字符數(shù)據(jù)了。
注意
在使用FileReader操作文本數(shù)據(jù)時(shí),該對(duì)象使用的是默認(rèn)的編碼表,如果要使用指定的編碼表,必須使用轉(zhuǎn)換流。
代碼體現(xiàn)
FileReader fr=new FileReader(“test.txt”);InputStreamReader isr=new InputStreamReader(new FileInputStreamReader(“test.txt”));
這兩句代碼意義相同,操作test.txt中的數(shù)據(jù)都是使用了系統(tǒng)默認(rèn)的編碼GBK。因?yàn)槲覀兿到y(tǒng)默認(rèn)使用的編碼表是GBK,如果test.txt中的數(shù)據(jù)是通過UTF-8形式編碼的,那么在讀取的時(shí)候就需要指定編碼表,因此轉(zhuǎn)換流必須使用InputStreamReader isr=newInputStreamReader(new FileInputStream(“a.txt”),”UTF-8”);
四、流操作的基本規(guī)律
|--明確數(shù)據(jù)源和數(shù)據(jù)匯(數(shù)據(jù)目的)
其實(shí)是為了明確是輸入流還是輸出流
|--明確操作的數(shù)據(jù)是否是純文本數(shù)據(jù)
|--說明
數(shù)據(jù)源
鍵盤System.in、硬盤、File開頭的流對(duì)象、內(nèi)存(數(shù)組)。
數(shù)據(jù)匯
控制臺(tái)System.out、硬盤、File開頭的流對(duì)象、內(nèi)存(數(shù)組)。
|--需求
將鍵盤錄入的數(shù)據(jù)存儲(chǔ)到一個(gè)文件中和打印到控制臺(tái)
|--數(shù)據(jù)源System.in
既然是源,使用的就是輸入流,可用的體系有InputStream、Reader。因?yàn)殒I盤錄入進(jìn)來的一定是純文本數(shù)據(jù),所以可以使用專門操作字符數(shù)據(jù)的Reader。而System.in對(duì)應(yīng)的流是字節(jié)讀取流,所以要將其進(jìn)行轉(zhuǎn)換,將字節(jié)轉(zhuǎn)換成字符即可,所以要使用Reader體系中的InputStreamReader,如果要提高效率,就使用BufferedReader,代碼如:
BufferedReader bur=new BufferedReader(newInputStreamReader(Sysem.in));
|--數(shù)據(jù)匯:一個(gè)文件、硬盤
數(shù)據(jù)匯一定是輸出流,可以用的體系有OutputStream、Writer。往文件中存儲(chǔ)的都是文本數(shù)據(jù),那么可以使用字符流較為方便Writer。因?yàn)椴僮鞯氖且粋€(gè)文件,所以使用Writer中的FileWriter,同理,要提高效率就要使用BufferedWriter。
代碼如:BufferedWriter bufr=new BufferedWriter(new
FileWriter(“test.txt”));
清單9,將鍵盤錄入的數(shù)據(jù)存儲(chǔ)到一個(gè)文件中和打印到控制臺(tái)代碼 private static void test7(){ BufferedReader bur=null;OutputStreamWriter osw=null;BufferedWriter bw=null;try{ //數(shù)據(jù)源
bur=new BufferedReader(new InputStreamReader(System.in));//數(shù)據(jù)匯
osw=new OutputStreamWriter(System.out);//數(shù)據(jù)匯,因?yàn)閿?shù)據(jù)源用的是系統(tǒng)默認(rèn)編碼,所以這里可以直接使用FileWriter //否則必須使用OutputStreamWriter轉(zhuǎn)換流
bw=new BufferedWriter(new FileWriter(“D: est_target.txt”));String line=null;while((line=bur.readLine())!=null){ osw.write(line);osw.flush();//刷新到控制臺(tái) bw.write(line);bw.flush();//刷新到文本文件 } }catch(IOException e){ e.toString();}finally{ try{ if(osw!=null){ osw.close();} if(bur!=null){ bur.close();} if(bw!=null){ bw.close();} }catch(IOException ex){ ex.toString();} } }
清單9是按照默認(rèn)編碼表寫入文本文件的,那么如何按照指定編碼表寫入文件呢?其實(shí)也很簡(jiǎn)單,將清單9的代碼稍微改一下就可以了。
清單10代碼
private static void test8(){ BufferedReader bur=null;BufferedWriter bw=null;try{ //數(shù)據(jù)源
bur=new BufferedReader(new InputStreamReader(System.in));//數(shù)據(jù)匯,按照指定編碼格式存儲(chǔ)到文本文件
bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(“D: est_target.txt”),“UTF-8”));String line=null;while((line=bur.readLine())!=null){ bw.write(line);bw.flush();//刷新到文本文件 } }catch(IOException e){ e.toString();}finally{ try{ if(bur!=null){ bur.close();} if(bw!=null){ bw.close();} }catch(IOException ex){ ex.toString();} } }
既然寫入文件時(shí)指定了編碼,那么在讀取的時(shí)候就必須指定該編碼才能正確顯示。
清單11,讀取指定編碼表的文件代碼 private static void test9(){ BufferedReader bur = null;try { // 注意,這里讀取的是清單8寫入的文件,// 清單10用UTF-8編碼格式寫入,// 所以在構(gòu)造InputStreamReader時(shí)必須指定UTF-8編碼 bur = new BufferedReader(new InputStreamReader(new FileInputStream(“D: est_target.txt”), “UTF-8”));String line = null;while((line = bur.readLine())!= null){ System.out.println(line);} } catch(IOException e){ e.toString();} finally { try { if(bur!= null){ bur.close();} } catch(IOException ex){ ex.toString();} } }
寫入和讀取都做了,現(xiàn)在還差個(gè)復(fù)制操作,其實(shí)復(fù)制文件也很簡(jiǎn)單,先讀取文件,再將讀取到的數(shù)據(jù)寫入文件,不同的是,在讀取和寫入時(shí)我們可以指定編碼表。
清單12代碼
private static void test11(){ BufferedReader bur = null;BufferedWriter buw = null;try { bur = new BufferedReader(new InputStreamReader(new FileInputStream(“D: est_target.txt”), “UTF-8”));buw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(“D: est_target1.txt”),“UTF-8”));String line = null;while((line = bur.readLine())!= null){ buw.write(line);buw.flush();// 刷新到文本文件 } } catch(IOException e){ e.toString();} finally { try { if(buw!= null){ buw.close();} if(bur!= null){ bur.close();} } catch(IOException ex){ ex.toString();} } }
第四篇:java 文件與輸入輸出流
實(shí)驗(yàn)2文件與輸入輸出流(1)
一、實(shí)驗(yàn)?zāi)康? 能夠使用File類表示文件或目錄,獲取相關(guān)信息,并進(jìn)行文件操作; ? 能夠利用InputStream和OutputStream的子類進(jìn)行字節(jié)讀、寫操作,明白其優(yōu)點(diǎn)及不足;
? 能夠用FileInputStream和FileOutputStream進(jìn)行文件讀寫的操作; ? 理解“逐層包裝”思想,能夠利用“數(shù)據(jù)流”(DataInputStream和DataOutputStream)包裝字節(jié)流,方便各類數(shù)據(jù)的讀寫;
? 能夠利用“緩沖字節(jié)流”(BufferedInputStream和BufferedOutputStream)包裝字節(jié)流,加快數(shù)據(jù)的讀寫速度;
? 熟知System.in和System.out是PrintStream的實(shí)例。
二、實(shí)驗(yàn)步驟
在Eclipse環(huán)境中導(dǎo)入項(xiàng)目“code(lab_2)”,然后按要求完成各小題:
1.打開FileTest.java文件,請(qǐng)按下列要求進(jìn)行操作:
(1)按要求填充程序所缺代碼;
(2)程序的運(yùn)行需要用到一個(gè)命令行參數(shù),請(qǐng)分別用一個(gè)文件、目錄作參數(shù)來運(yùn)行程序,看一看結(jié)果有什么不同。
(在Eclipse中設(shè)置命令行參數(shù)方法:Run/Open Run Dialog ?/(x)=Arguments設(shè)置)
2.在上一題的基礎(chǔ)上,修改程序,使之具備輸出指定目錄下所有子目錄中文件絕對(duì)路徑名、大小的功能,如下所示:
子目錄:C:jdk1.6.0sample
子目錄:C:jdk1.6.0samplewebservices
子目錄:C:jdk1.6.0samplewebservicesEbayServer
文件: C:jdk1.6.0samplewebservicesEbayServerbuild.properties,大小: 512 字節(jié) 文件: C:jdk1.6.0samplewebservicesEbayServerbuild.xml,大小: 3168 字節(jié)1
……
提示:參考課件 FileSpace.java內(nèi)容,通過一個(gè)以“路徑名”為參數(shù)的靜態(tài)方法來實(shí)現(xiàn):該方法先判斷“路徑名”是一個(gè)文件,還是一個(gè)目錄?如果是文件,則輸出其絕對(duì)路徑和大??;若為一個(gè)目錄,則先顯示目錄絕對(duì)路徑,再列出該目錄下的所有子目錄和文件,通過循環(huán)和遞歸方法來執(zhí)行后續(xù)處理。
3.文件FileOutputStreamTest.java的功能是:利用FileOutputStream類向myfile.txt文件寫入'0'~'9'和“用字節(jié)流寫入文件內(nèi)容”,請(qǐng)?zhí)畛涑绦蛩贝a,并運(yùn)行程序。然后打開myfile.txt文件,查看其內(nèi)容是否與要求相符?
4.文件FileInputStreamTest1.java的功能是:利用FileInputStream類以“逐字節(jié)”方式讀取myfile.txt文件內(nèi)容,并輸出。請(qǐng)?zhí)畛涑绦蛩贝a,并運(yùn)行程序。問題:為什么程序輸出的內(nèi)容為亂碼?
5.在FileInputStreamTest1.java的基礎(chǔ)上,編寫程序FileInputStreamTest2.java,利用FileInputStream類以“字節(jié)數(shù)組”方式讀取myfile.txt文件內(nèi)容,能正確輸出,解決亂碼問題。
思考題:亂碼問題是怎樣解決的?
6.若要將信息“Java開發(fā)典型模塊大全”(書名)、“明日科技”(作者)、79.5(價(jià)格)等信息以UTF、double類型保存到文件books.txt中,請(qǐng)用“數(shù)據(jù)流”類編程實(shí)現(xiàn)。
第五篇:JAVA(IO流方法)
package Stream;
import java.io.*;
public class Io {
public void test1()throws Exception{
File file=new File(“E:/txt.txt”);
if(file.exists()){
System.out.println(“是否是文件:”+file.isFile());
System.out.println(“文件名是:”+file.getName());
System.out.println(“路徑是:”+file.getPath());
System.out.println(“絕對(duì)路徑是:”+file.getAbsolutePath());System.out.println(“上級(jí)目錄是:”+file.getParent());System.out.println(“文件大小是:”+file.length()+“字節(jié)”);}
else {
file.createNewFile();
}
}
public void test2()throws Exception{//以字節(jié)流方式讀取
File file=new File(“E:/txt1.txt”);
FileInputStream fi=new FileInputStream(file);
byte[] content= new byte[fi.available()];
/*for(int i=0;i content[i]=(byte)fi.read(); }//讀取長(zhǎng)度后,將其轉(zhuǎn)換成字符型 *///第一種方式 fi.read(content);//第二種方式 String str=new String(content); System.out.println(str.trim()); } public void test3()throws Exception{//以字節(jié)流方式寫入數(shù)據(jù) File file=new File(“E:/txt1.txt”); FileOutputStream fo=new FileOutputStream(file); byte[]content=new String(“你是一個(gè)”).getBytes(); fo.write(content); content=new String(“呵呵”).getBytes(); fo.write(content); fo.close(); } public void test4()throws Exception{//用的緩沖方式文本讀取 FileReader file=new FileReader(“E:/txt1.txt”); BufferedReader br=new BufferedReader(file); StringBuffer str=new StringBuffer(); String sw=br.readLine(); if(sw!=null){ str.append(sw+“ n”); } System.out.println(str); } public void test5()throws Exception{//用緩沖的方式寫入數(shù)據(jù)然后再讀入數(shù)據(jù) FileWriter file=new FileWriter(“E:/txt1.txt”); BufferedWriter bw=new BufferedWriter(file); for(int i=1;i<=10;i++){ bw.write(“這是第”+i+“行”); bw.newLine(); } bw.close();//寫放數(shù)據(jù) FileReader file1=new FileReader(“E:/txt1.txt”); BufferedReader br=new BufferedReader(file1); StringBuffer str=new StringBuffer(); String sw=br.readLine(); if(sw!=null){ str.append(sw+“ n”); } System.out.println(str); } public void test6(){//刪除文件 File file=new File(“E:/text.txt”); if(file.exists()){ System.out.println(“開始刪除文件 :”+file.getPath());if(file.delete()){ System.out.println(“文件刪除成功”); } else { System.out.println(“文件刪除失敗”); } } else { System.out.println(“該文件不存在”); } } public void test7()throws Exception{//創(chuàng)建 一個(gè)文件夾---創(chuàng)建一個(gè)目錄或路徑 File file=new File(“E:/txt1.txt”); if(file.exists()==false){ file.createNewFile(); } } public void test8()throws Exception {//* 將txt.txt復(fù)制文件到txt12.txt去;以字節(jié)流的的形式復(fù)制 File file=new File(“E:/txt.txt”); FileInputStream fi=new FileInputStream(file); byte[] content= new byte[fi.available()]; fi.read(content); fi.read(content, 0, content.length); String str=new String(content); System.out.println(str); File file1=new File(“E:/txt12.txt”); if(file.exists()==false){ file.createNewFile(); }//如果不存在該文件則創(chuàng)建一件文件 再行進(jìn)復(fù)制 FileOutputStream fo=new FileOutputStream(file1,true);fo.write(content); fo.flush(); fo.close(); fi.close();//關(guān)閉流 } public void test9()throws Exception {//另和種方式復(fù)制文件--從緩沖的形式復(fù)制 FileReader file=new FileReader(“E:/txt.txt”); BufferedReader br=new BufferedReader(file); String str=br.readLine(); //從文件 里面讀取出來 FileWriter file1=new FileWriter(“E:/txt1.txt”); BufferedWriter bw=new BufferedWriter(file1); while(str!=null){ bw.write(str); bw.newLine(); str = br.readLine(); } bw.flush(); bw.close(); br.close(); } public void test10()throws Exception{ File file=new File(“E:/txt.txt”); InputStream is = new FileInputStream(file); byte[] array = new byte[3]; int hasRead = 0; File file1=new File(“E:/txt1.txt”); OutputStream os = new FileOutputStream(file1); while((hasRead=is.read(array, 0, array.length))!=-1) { System.out.println(“讀取了”+hasRead+“個(gè)字節(jié)”); for(int i=0;i { System.out.println(“第”+(i+1)+“個(gè):”+array[i]); } /**每次從數(shù)組array里寫入字節(jié)到文件 讀多少寫多少*/ os.write(array, 0, hasRead); } os.flush(); os.close(); is.close(); } public static void main(String args[])throws Exception{ Io t=new Io(); t.test9(); } }