全面總結(jié)java IO體系
1.Java Io流的概念,分類(lèi),類(lèi)圖。
1.1 Java Io流的概念
java的io是實(shí)現(xiàn)輸入和輸出的基礎(chǔ),可以方便的實(shí)現(xiàn)數(shù)據(jù)的輸入和輸出操作。在java中把不同的輸入/輸出源(鍵盤(pán),文件,網(wǎng)絡(luò)連接等)抽象表述為“流”(stream)。通過(guò)流的形式允許java程序使用相同的方式來(lái)訪問(wèn)不同的輸入/輸出源。stram是從起源(source)到接收的(sink)的有序數(shù)據(jù)。
注:java把所有的傳統(tǒng)的流類(lèi)型都放到在java io包下,用于實(shí)現(xiàn)輸入和輸出功能。
1.2 Io流的分類(lèi):
按照不同的分類(lèi)方式,可以把流分為不同的類(lèi)型。常用的分類(lèi)有三種:
1.2.1 按照流的流向分,可以分為輸入流和輸出流。
- 輸入流: 只能從中讀取數(shù)據(jù),而不能向其寫(xiě)入數(shù)據(jù)。
- 輸出流:只能向其寫(xiě)入數(shù)據(jù),而不能向其讀取數(shù)據(jù)。
此處的輸入,輸出涉及一個(gè)方向的問(wèn)題,對(duì)于如圖15.1所示的數(shù)據(jù)流向,數(shù)據(jù)從內(nèi)存到硬盤(pán),通常稱(chēng)為輸出流——也就是說(shuō),這里的輸入,輸出都是從程序運(yùn)行所在的內(nèi)存的角度來(lái)劃分的。
注:如果從硬盤(pán)的角度來(lái)考慮,圖15.1所示的數(shù)據(jù)流應(yīng)該是輸入流才對(duì);但劃分輸入/輸出流時(shí)是從程序運(yùn)行所在的內(nèi)存的角度來(lái)考慮的,因此如圖15.1所在的流時(shí)輸出流。而不是輸入流。
對(duì)于如圖15.2所示的數(shù)據(jù)流向,數(shù)據(jù)從服務(wù)器通過(guò)網(wǎng)絡(luò)流向客戶(hù)端,在這種情況下,Server端的內(nèi)存負(fù)責(zé)將數(shù)據(jù)輸出到網(wǎng)絡(luò)里,因此Server端的程序使用輸出流;Client端的內(nèi)存負(fù)責(zé)從網(wǎng)絡(luò)中讀取數(shù)據(jù),因此Client端的程序應(yīng)該使用輸入流。
注:java的輸入流主要是InputStream和Reader作為基類(lèi),而輸出流則是主要由outputStream和Writer作為基類(lèi)。它們都是一些抽象基類(lèi),無(wú)法直接創(chuàng)建實(shí)例。
1.2.2 按照操作單元?jiǎng)澐?,可以劃分為字?jié)流和字符流。
字節(jié)流和字符流的用法幾乎完成全一樣,區(qū)別在于字節(jié)流和字符流所操作的數(shù)據(jù)單元不同,字節(jié)流操作的單元是數(shù)據(jù)單元是8位的字節(jié),字符流操作的是數(shù)據(jù)單元為16位的字符。
字節(jié)流主要是由InputStream和outPutStream作為基類(lèi),而字符流則主要有Reader和Writer作為基類(lèi)。
1.2.3 按照流的角色劃分為節(jié)點(diǎn)流和處理流。
可以從/向一個(gè)特定的IO設(shè)備(如磁盤(pán),網(wǎng)絡(luò))讀/寫(xiě)數(shù)據(jù)的流,稱(chēng)為節(jié)點(diǎn)流。節(jié)點(diǎn)流也被稱(chēng)為低級(jí)流。圖15.3顯示了節(jié)點(diǎn)流的示意圖。
從圖15.3中可以看出,當(dāng)使用節(jié)點(diǎn)流進(jìn)行輸入和輸出時(shí),程序直接連接到實(shí)際的數(shù)據(jù)源,和實(shí)際的輸入/輸出節(jié)點(diǎn)連接。
處理流則用于對(duì)一個(gè)已存在的流進(jìn)行連接和封裝,通過(guò)封裝后的流來(lái)實(shí)現(xiàn)數(shù)據(jù)的讀/寫(xiě)功能。處理流也被稱(chēng)為高級(jí)流。圖15.4顯示了處理流的示意圖。
從圖15.4可以看出,當(dāng)使用處理流進(jìn)行輸入/輸出時(shí),程序并不會(huì)直接連接到實(shí)際的數(shù)據(jù)源,沒(méi)有和實(shí)際的輸入和輸出節(jié)點(diǎn)連接。使用處理流的一個(gè)明顯的好處是,只要使用相同的處理流,程序就可以采用完全相同的輸入/輸出代碼來(lái)訪問(wèn)不同的數(shù)據(jù)源,隨著處理流所包裝的節(jié)點(diǎn)流的變化,程序?qū)嶋H所訪問(wèn)的數(shù)據(jù)源也相應(yīng)的發(fā)生變化。
1.3 流的原理淺析和常用的流的分類(lèi)表:
1.3.1 流的原理淺析:
java Io流共涉及40多個(gè)類(lèi),這些類(lèi)看上去很雜亂,但實(shí)際上很有規(guī)則,而且彼此之間存在非常緊密的聯(lián)系, Java Io流的40多個(gè)類(lèi)都是從如下4個(gè)抽象類(lèi)基類(lèi)中派生出來(lái)的。
- InputStream/Reader: 所有的輸入流的基類(lèi),前者是字節(jié)輸入流,后者是字符輸入流。
- OutputStream/Writer: 所有輸出流的基類(lèi),前者是字節(jié)輸出流,后者是字符輸出流。
對(duì)于InputStream和Reader而言,它們把輸入設(shè)備抽象成為一個(gè)”水管“,這個(gè)水管的每個(gè)“水滴”依次排列,如圖15.5所示:從圖15.5可以看出,字節(jié)流和字符流的處理方式其實(shí)很相似,只是它們處理的輸入/輸出單位不同而已。輸入流使用隱式的記錄指針來(lái)表示當(dāng)前正準(zhǔn)備從哪個(gè)“水滴”開(kāi)始讀取,每當(dāng)程序從InputStream或者Reader里面取出一個(gè)或者多個(gè)“水滴”后,記錄指針自定向后移動(dòng);除此之外,InputStream和Reader里面都提供了一些方法來(lái)控制記錄指針的移動(dòng)。
對(duì)于OutputStream和Writer而言,它們同樣把輸出設(shè)備抽象成一個(gè)”水管“,只是這個(gè)水管里面沒(méi)有任何水滴,如圖15.6所示:
正如圖15.6所示,當(dāng)執(zhí)行輸出時(shí),程序相當(dāng)于依次把“水滴”放入到輸出流的水管中,輸出流同樣采用隱示指針來(lái)標(biāo)識(shí)當(dāng)前水滴即將放入的位置,每當(dāng)程序向OutputStream或者Writer里面輸出一個(gè)或者多個(gè)水滴后,記錄指針自動(dòng)向后移動(dòng)。
圖15.5和圖15.6顯示了java Io的基本概念模型,除此之外,Java的處理流模型則體現(xiàn)了Java輸入和輸出流設(shè)計(jì)的靈活性。處理流的功能主要體現(xiàn)在以下兩個(gè)方面。
- 性能的提高:主要以增加緩沖的方式來(lái)提供輸入和輸出的效率。
- 操作的便捷:處理流可能提供了一系列便捷的方法來(lái)一次輸入和輸出大批量的內(nèi)容,而不是輸入/輸出一個(gè)或者多個(gè)“水滴”。
處理流可以“嫁接”在任何已存在的流的基礎(chǔ)之上,這就允許Java應(yīng)用程序采用相同的代碼,透明的方式來(lái)訪問(wèn)不同的輸入和輸出設(shè)備的數(shù)據(jù)流。圖15.7顯示了處理流的模型。
1.3.2 java輸入/輸出流體系中常用的流的分類(lèi)表
分類(lèi) | 字節(jié)輸入流 | 字節(jié)輸出流 | 字符輸入流 | 字符輸出流 |
---|---|---|---|---|
抽象基類(lèi) | InputStream | OutputStream | Reader | Writer |
訪問(wèn)文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
訪問(wèn)數(shù)組 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
訪問(wèn)管道 | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter |
訪問(wèn)字符串 | StringReader | StringWriter | ||
緩沖流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
轉(zhuǎn)換流 | InputStreamReader | OutputStreamWriter | ||
對(duì)象流 | ObjectInputStream | ObjectOutputStream | ||
抽象基類(lèi) | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter |
打印流 | PrintStream | PrintWriter | ||
推回輸入流 | PushbackInputStream | PushbackReader | ||
特殊流 | DataInputStream | DataOutputStream |
注:表中粗體字所標(biāo)出的類(lèi)代表節(jié)點(diǎn)流,必須直接與指定的物理節(jié)點(diǎn)關(guān)聯(lián):斜體字標(biāo)出的類(lèi)代表抽象基類(lèi),無(wú)法直接創(chuàng)建實(shí)例。
2.常用的io流的用法
下面是整理的常用的Io流的特性及使用方法,只有清楚每個(gè)Io流的特性和方法。才能在不同的需求面前正確的選擇對(duì)應(yīng)的IO流進(jìn)行開(kāi)發(fā)。
2.1 Io體系的基類(lèi)(InputStream/Reader,OutputStream/Writer)
字節(jié)流和字符流的操作方式基本一致,只是操作的數(shù)據(jù)單元不同——字節(jié)流的操作單元是字節(jié),字符流的操作單元是字符。所以字節(jié)流和字符流就整理在一起了。
InputStream和Reader是所有輸入流的抽象基類(lèi),本身并不能創(chuàng)建實(shí)例來(lái)執(zhí)行輸入,但它們將成為所有輸入流的模板,所以它們的方法是所有輸入流都可使用的方法。
在InputStream里面包含如下3個(gè)方法。
- int read(); 從輸入流中讀取單個(gè)字節(jié)(相當(dāng)于從圖15.5所示的水管中取出一滴水),返回所讀取的字節(jié)數(shù)據(jù)(字節(jié)數(shù)據(jù)可直接轉(zhuǎn)換為int類(lèi)型)。
- int read(byte[] b)從輸入流中最多讀取b.length個(gè)字節(jié)的數(shù)據(jù),并將其存儲(chǔ)在字節(jié)數(shù)組b中,返回實(shí)際讀取的字節(jié)數(shù)。
- int read(byte[] b,int off,int len); 從輸入流中最多讀取len個(gè)字節(jié)的數(shù)據(jù),并將其存儲(chǔ)在數(shù)組b中,放入數(shù)組b中時(shí),并不是從數(shù)組起點(diǎn)開(kāi)始,而是從off位置開(kāi)始,返回實(shí)際讀取的字節(jié)數(shù)。
在Reader中包含如下3個(gè)方法。
- int read(); 從輸入流中讀取單個(gè)字符(相當(dāng)于從圖15.5所示的水管中取出一滴水),返回所讀取的字符數(shù)據(jù)(字節(jié)數(shù)據(jù)可直接轉(zhuǎn)換為int類(lèi)型)。
- int read(char[] b)從輸入流中最多讀取b.length個(gè)字符的數(shù)據(jù),并將其存儲(chǔ)在字節(jié)數(shù)組b中,返回實(shí)際讀取的字符數(shù)。
- int read(char[] b,int off,int len); 從輸入流中最多讀取len個(gè)字符的數(shù)據(jù),并將其存儲(chǔ)在數(shù)組b中,放入數(shù)組b中時(shí),并不是從數(shù)組起點(diǎn)開(kāi)始,而是從off位置開(kāi)始,返回實(shí)際讀取的字符數(shù)。
對(duì)比InputStream和Reader所提供的方法,就不難發(fā)現(xiàn)這兩個(gè)基類(lèi)的功能基本是一樣的。InputStream和Reader都是將輸入數(shù)據(jù)抽象成如圖15.5所示的水管,所以程序即可以通過(guò)read()方法每次讀取一個(gè)”水滴“,也可以通過(guò)read(char[] chuf)或者read(byte[] b)方法來(lái)讀取多個(gè)“水滴”。
當(dāng)使用數(shù)組作為read()方法中的參數(shù), 我們可以理解為使用一個(gè)“竹筒”到如圖15.5所示的水管中取水,如圖15.8所示read(char[] cbuf)方法的參數(shù)可以理解成一個(gè)”竹筒“,程序每次調(diào)用輸入流read(char[] cbuf)或read(byte[] b)方法,就相當(dāng)于用“竹筒”從輸入流中取出一筒“水滴”,程序得到“竹筒”里面的”水滴“后,轉(zhuǎn)換成相應(yīng)的數(shù)據(jù)即可;
程序多次重復(fù)這個(gè)“取水”過(guò)程,直到最后。程序如何判斷取水取到了最后呢?直到read(char[] chuf)或者read(byte[] b)方法返回-1,即表明到了輸入流的結(jié)束點(diǎn)。
InputStream和Reader提供的一些移動(dòng)指針的方法:
- void mark(int readAheadLimit); 在記錄指針當(dāng)前位置記錄一個(gè)標(biāo)記(mark)。
- boolean markSupported(); 判斷此輸入流是否支持mark()操作,即是否支持記錄標(biāo)記。
- void reset(); 將此流的記錄指針重新定位到上一次記錄標(biāo)記(mark)的位置。
- long skip(long n); 記錄指針向前移動(dòng)n個(gè)字節(jié)/字符。
OutputStream和Writer:
OutputStream和Writer的用法也非常相似,它們采用如圖15.6所示的模型來(lái)執(zhí)行輸入,兩個(gè)流都提供了如下三個(gè)方法:
- void write(int c); 將指定的字節(jié)/字符輸出到輸出流中,其中c即可以代表字節(jié),也可以代表字符。
- void write(byte[]/char[] buf); 將字節(jié)數(shù)組/字符數(shù)組中的數(shù)據(jù)輸出到指定輸出流中。
- void write(byte[]/char[] buf, int off,int len ); 將字節(jié)數(shù)組/字符數(shù)組中從off位置開(kāi)始,長(zhǎng)度為len的字節(jié)/字符輸出到輸出流中。
因?yàn)樽址髦苯右宰址鳛椴僮鲉挝唬訵riter可以用字符串來(lái)代替字符數(shù)組,即以String對(duì)象作為參數(shù)。Writer里面還包含如下兩個(gè)方法。
- void write(String str); 將str字符串里包含的字符輸出到指定輸出流中。
- void write (String str, int off, int len); 將str字符串里面從off位置開(kāi)始,長(zhǎng)度為len的字符輸出到指定輸出流中。
2.2 Io體系的基類(lèi)文件流的使用(FileInputStream/FileReader ,F(xiàn)ileOutputStream/FileWriter)
前面說(shuō)過(guò)InputStream和Reader都是抽象類(lèi),本身不能創(chuàng)建實(shí)例,但它們分別有一個(gè)用于讀取文件的輸入流:FileInputStream和FileReader,它們都是節(jié)點(diǎn)流——會(huì)直接和指定文件關(guān)聯(lián)。下面程序示范使用FileInputStream和FileReader。
使用FileInputStream讀取文件:
public class MyClass { public static void main(String[] args)throws IOException{ FileInputStream fis=null; try { //創(chuàng)建字節(jié)輸入流 fis=new FileInputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\Test.txt"); //創(chuàng)建一個(gè)長(zhǎng)度為1024的竹筒 byte[] b=new byte[1024]; //用于保存的實(shí)際字節(jié)數(shù) int hasRead=0; //使用循環(huán)來(lái)重復(fù)取水的過(guò)程 while((hasRead=fis.read(b))>0){ //取出竹筒中的水滴(字節(jié)),將字節(jié)數(shù)組轉(zhuǎn)換成字符串進(jìn)行輸出 System.out.print(new String(b,0,hasRead)); } }catch (IOException e){ e.printStackTrace(); }finally { fis.close(); } } }
注:上面程序最后使用了fis.close()來(lái)關(guān)閉該文件的輸入流,與JDBC編程一樣,程序里面打開(kāi)的文件IO資源不屬于內(nèi)存的資源,垃圾回收機(jī)制無(wú)法回收該資源,所以應(yīng)該顯示的關(guān)閉打開(kāi)的IO資源。Java 7改寫(xiě)了所有的IO資源類(lèi),它們都實(shí)現(xiàn)了AntoCloseable接口,因此都可以通過(guò)自動(dòng)關(guān)閉資源的try語(yǔ)句來(lái)關(guān)閉這些Io流。
使用FileReader讀取文件:
public class FileReaderTest { public static void main(String[] args)throws IOException{ FileReader fis=null; try { //創(chuàng)建字節(jié)輸入流 fis=new FileReader("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\Test.txt"); //創(chuàng)建一個(gè)長(zhǎng)度為1024的竹筒 char[] b=new char[1024]; //用于保存的實(shí)際字節(jié)數(shù) int hasRead=0; //使用循環(huán)來(lái)重復(fù)取水的過(guò)程 while((hasRead=fis.read(b))>0){ //取出竹筒中的水滴(字節(jié)),將字節(jié)數(shù)組轉(zhuǎn)換成字符串進(jìn)行輸出 System.out.print(new String(b,0,hasRead)); } }catch (IOException e){ e.printStackTrace(); }finally { fis.close(); } } }
可以看出使用FileInputStream和FileReader進(jìn)行文件的讀寫(xiě)并沒(méi)有什么區(qū)別,只是操作單元不同而且。
FileOutputStream/FileWriter是Io中的文件輸出流,下面介紹這兩個(gè)類(lèi)的用法。
FileOutputStream的用法:
public class FileOutputStreamTest { public static void main(String[] args)throws IOException { FileInputStream fis=null; FileOutputStream fos=null; try { //創(chuàng)建字節(jié)輸入流 fis=new FileInputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\Test.txt"); //創(chuàng)建字節(jié)輸出流 fos=new FileOutputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\newTest.txt"); byte[] b=new byte[1024]; int hasRead=0; //循環(huán)從輸入流中取出數(shù)據(jù) while((hasRead=fis.read(b))>0){ //每讀取一次,即寫(xiě)入文件輸入流,讀了多少,就寫(xiě)多少。 fos.write(b,0,hasRead); } }catch (IOException e){ e.printStackTrace(); }finally { fis.close(); fos.close(); } } }
運(yùn)行程序可以看到輸出流指定的目錄下多了一個(gè)文件:newTest.txt, 該文件的內(nèi)容和Test.txt文件的內(nèi)容完全相同。FileWriter的使用方式和FileOutputStream基本類(lèi)似,這里就帶過(guò)。
注:使用java的io流執(zhí)行輸出時(shí),不要忘記關(guān)閉輸出流,關(guān)閉輸出流除了可以保證流的物理資源被回收之外,可能還可以將輸出流緩沖區(qū)中的數(shù)據(jù)flush到物理節(jié)點(diǎn)中里(因?yàn)樵趫?zhí)行close()方法之前,自動(dòng)執(zhí)行輸出流的flush()方法)。java很多輸出流默認(rèn)都提供了緩存功能,其實(shí)我們沒(méi)有必要刻意去記憶哪些流有緩存功能,哪些流沒(méi)有,只有正常關(guān)閉所有的輸出流即可保證程序正常。
緩沖流的使用(BufferedInputStream/BufferedReader, BufferedOutputStream/BufferedWriter):
下面介紹字節(jié)緩存流的用法(字符緩存流的用法和字節(jié)緩存流一致就不介紹了):
public class BufferedStreamTest { public static void main(String[] args)throws IOException { FileInputStream fis=null; FileOutputStream fos=null; BufferedInputStream bis=null; BufferedOutputStream bos=null; try { //創(chuàng)建字節(jié)輸入流 fis=new FileInputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\Test.txt"); //創(chuàng)建字節(jié)輸出流 fos=new FileOutputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\newTest.txt"); //創(chuàng)建字節(jié)緩存輸入流 bis=new BufferedInputStream(fis); //創(chuàng)建字節(jié)緩存輸出流 bos=new BufferedOutputStream(fos); byte[] b=new byte[1024]; int hasRead=0; //循環(huán)從緩存流中讀取數(shù)據(jù) while((hasRead=bis.read(b))>0){ //向緩存流中寫(xiě)入數(shù)據(jù),讀取多少寫(xiě)入多少 bos.write(b,0,hasRead); } }catch (IOException e){ e.printStackTrace(); }finally { bis.close(); bos.close(); } } }
可以看到使用字節(jié)緩存流讀取和寫(xiě)入數(shù)據(jù)的方式和文件流(FileInputStream,FileOutputStream)并沒(méi)有什么不同,只是把處理流套接到文件流上進(jìn)行讀寫(xiě)。緩存流的原理下節(jié)介紹。
上面代碼中我們使用了緩存流和文件流,但是我們只關(guān)閉了緩存流。這個(gè)需要注意一下,當(dāng)我們使用處理流套接到節(jié)點(diǎn)流上的使用的時(shí)候,只需要關(guān)閉最上層的處理就可以了。java會(huì)自動(dòng)幫我們關(guān)閉下層的節(jié)點(diǎn)流。
2.3 轉(zhuǎn)換流的使用(InputStreamReader/OutputStreamWriter):
下面以獲取鍵盤(pán)輸入為例來(lái)介紹轉(zhuǎn)換流的用法。java使用System.in代表輸入。即鍵盤(pán)輸入,但這個(gè)標(biāo)準(zhǔn)輸入流是InputStream類(lèi)的實(shí)例,使用不太方便,而且鍵盤(pán)輸入內(nèi)容都是文本內(nèi)容,所以可以使用InputStreamReader將其包裝成BufferedReader,利用BufferedReader的readLine()方法可以一次讀取一行內(nèi)容,如下代碼所示:
public class InputStreamReaderTest { public static void main(String[] args)throws IOException { try { // 將System.in對(duì)象轉(zhuǎn)化為Reader對(duì)象 InputStreamReader reader=new InputStreamReader(System.in); //將普通的Reader包裝成BufferedReader BufferedReader bufferedReader=new BufferedReader(reader); String buffer=null; while ((buffer=bufferedReader.readLine())!=null){ // 如果讀取到的字符串為“exit”,則程序退出 if(buffer.equals("exit")){ System.exit(1); } //打印讀取的內(nèi)容 System.out.print("輸入內(nèi)容:"+buffer); } }catch (IOException e){ e.printStackTrace(); }finally { } } }
上面程序?qū)ystem.in包裝成BufferedReader,BufferedReader流具有緩存功能,它可以一次讀取一行文本——以換行符為標(biāo)志,如果它沒(méi)有讀到換行符,則程序堵塞。等到讀到換行符為止。運(yùn)行上面程序可以發(fā)現(xiàn)這個(gè)特征,當(dāng)我們?cè)诳刂婆_(tái)執(zhí)行輸入時(shí),只有按下回車(chē)鍵,程序才會(huì)打印出剛剛輸入的內(nèi)容。
2.4 對(duì)象流的使用(ObjectInputStream/ObjectOutputStream)的使用:
寫(xiě)入對(duì)象:
public static void writeObject(){ OutputStream outputStream=null; BufferedOutputStream buf=null; ObjectOutputStream obj=null; try { //序列化文件輸出流 outputStream=new FileOutputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\myfile.tmp"); //構(gòu)建緩沖流 buf=new BufferedOutputStream(outputStream); //構(gòu)建字符輸出的對(duì)象流 obj=new ObjectOutputStream(buf); //序列化數(shù)據(jù)寫(xiě)入 obj.writeObject(new Person("A", 21));//Person對(duì)象 //關(guān)閉流 obj.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
讀取對(duì)象:
/** * 讀取對(duì)象 */ public static void readObject() throws IOException { try { InputStream inputStream=new FileInputStream("E:\\learnproject\\Iotest\\lib\\src\\main\\java\\com\\myfile.tmp"); //構(gòu)建緩沖流 BufferedInputStream buf=new BufferedInputStream(inputStream); //構(gòu)建字符輸入的對(duì)象流 ObjectInputStream obj=new ObjectInputStream(buf); Person tempPerson=(Person)obj.readObject(); System.out.println("Person對(duì)象為:"+tempPerson); //關(guān)閉流 obj.close(); buf.close(); inputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
使用對(duì)象流的一些注意事項(xiàng)
1.讀取順序和寫(xiě)入順序一定要一致,不然會(huì)讀取出錯(cuò)。
2.在對(duì)象屬性前面加transient關(guān)鍵字,則該對(duì)象的屬性不會(huì)被序列化。
4.何為NIO,和傳統(tǒng)Io有何區(qū)別?
我們使用InputStream從輸入流中讀取數(shù)據(jù)時(shí),如果沒(méi)有讀取到有效的數(shù)據(jù),程序?qū)⒃诖颂幾枞摼€程的執(zhí)行。其實(shí)傳統(tǒng)的輸入里和輸出流都是阻塞式的進(jìn)行輸入和輸出。 不僅如此,傳統(tǒng)的輸入流、輸出流都是通過(guò)字節(jié)的移動(dòng)來(lái)處理的(即使我們不直接處理字節(jié)流,但底層實(shí)現(xiàn)還是依賴(lài)于字節(jié)處理),也就是說(shuō),面向流的輸入和輸出一次只能處理一個(gè)字節(jié),因此面向流的輸入和輸出系統(tǒng)效率通常不高。
從JDk1.4開(kāi)始,java提供了一系列改進(jìn)的輸入和輸出處理的新功能,這些功能被統(tǒng)稱(chēng)為新IO(NIO)。新增了許多用于處理輸入和輸出的類(lèi),這些類(lèi)都被放在java.nio包及其子包下,并且對(duì)原io的很多類(lèi)都以NIO為基礎(chǔ)進(jìn)行了改寫(xiě)。新增了滿(mǎn)足NIO的功能。
NIO采用了內(nèi)存映射對(duì)象的方式來(lái)處理輸入和輸出,NIO將文件或者文件的一塊區(qū)域映射到內(nèi)存中,這樣就可以像訪問(wèn)內(nèi)存一樣來(lái)訪問(wèn)文件了。通過(guò)這種方式來(lái)進(jìn)行輸入/輸出比傳統(tǒng)的輸入和輸出要快的多。
JDk1.4使用NIO改寫(xiě)了傳統(tǒng)Io后,傳統(tǒng)Io的讀寫(xiě)速度和NIO差不了太多。
5.在開(kāi)發(fā)中正確使用Io流
了解了java io的整體類(lèi)結(jié)構(gòu)和每個(gè)類(lèi)的一下特性后,我們可以在開(kāi)發(fā)的過(guò)程中根據(jù)需要靈活的使用不同的Io流進(jìn)行開(kāi)發(fā)。下面是我整理2點(diǎn)原則:
- 如果是操作二進(jìn)制文件那我們就使用字節(jié)流,如果操作的是文本文件那我們就使用字符流。
- 盡可能的多使用處理流,這會(huì)使我們的代碼更加靈活,復(fù)用性更好。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java8中Optional類(lèi)型和Kotlin中可空類(lèi)型的使用對(duì)比
- 深入理解Java注解類(lèi)型(@Annotation)
- Java中的collection集合類(lèi)型總結(jié)
- Java如何使用Optional與Stream取代if判空邏輯(JDK8以上)
- Java Jedis NOAUTH Authentication required問(wèn)題解決方法
- 使用IDEA異常斷點(diǎn)來(lái)定位java.lang.ArrayStoreException的問(wèn)題
- Spring中基于Java的配置@Configuration和@Bean用法詳解
- JAVA IO的3種類(lèi)型區(qū)別解析
相關(guān)文章
java多線程并發(fā)executorservice(任務(wù)調(diào)度)類(lèi)
這篇文章主要介紹了線程并發(fā)ScheduledExecutorService類(lèi),設(shè)置 ScheduledExecutorService ,2秒后,在 1 分鐘內(nèi)每 10 秒鐘蜂鳴一次2014-01-01Springboot Mybatis-Plus數(shù)據(jù)庫(kù)單元測(cè)試實(shí)戰(zhàn)(三種方式)
這篇文章主要介紹了Springboot Mybatis-Plus數(shù)據(jù)庫(kù)單元測(cè)試實(shí)戰(zhàn)(三種方式),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12詳解JSON與?Java對(duì)象之間的轉(zhuǎn)化
在現(xiàn)在的日常開(kāi)發(fā)中,不管前端還是后端,JSON?格式的數(shù)據(jù)是用得比較多的,甚至可以說(shuō)無(wú)處不在。所以本文主要來(lái)講講JSON?格式的數(shù)據(jù)與?Java?對(duì)象之間的轉(zhuǎn)化吧2023-03-03Spring MVC的參數(shù)綁定和返回值問(wèn)題
這篇文章主要介紹了Spring MVC的參數(shù)綁定和返回值問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02java基于Socket做一個(gè)簡(jiǎn)單下載器
這篇文章主要為大家詳細(xì)介紹了java如何基于Socket制作一個(gè)簡(jiǎn)單下載器,感興趣的小伙伴們可以參考一下2016-08-08