您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關(guān)JAVA IO體系是怎樣的,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。
基于字節(jié)的IO操作
基于字符的IO操作
從上圖可以看到,整個(gè)Java IO體系都是基于字節(jié)流(InputStream/OutputStream) 和 字符流(Reader/Writer)作為基類,根據(jù)不同的數(shù)據(jù)載體或功能派生出來(lái)的。
----------------------------------------------------------------------------------------------------------------------------------------------------------------
文件流:FileInputStream/FileOutputStream, FileReader/FileWriter
這四個(gè)類是專門操作文件流的,用法高度相似,區(qū)別在于前面兩個(gè)是操作字節(jié)流,后面兩個(gè)是操作字符流。它們都會(huì)直接操作文件流,直接與OS底層交互。因此他們也被稱為節(jié)點(diǎn)流。
注意使用這幾個(gè)流的對(duì)象之后,需要關(guān)閉流對(duì)象,因?yàn)閖ava垃圾回收器不會(huì)主動(dòng)回收。不過在Java7之后,可以在 try() 括號(hào)中打開流,最后程序會(huì)自動(dòng)關(guān)閉流對(duì)象,不再需要顯示地close。
下面演示這四個(gè)流對(duì)象的基本用法,
package io; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class TestIO { public static void FileInputStreamTest() throws IOException { FileInputStream fis = new FileInputStream("tmp2.txt"); byte[] buf = new byte[1024]; int hasRead = 0; //read()返回的是單個(gè)字節(jié)數(shù)據(jù)(字節(jié)數(shù)據(jù)可以直接專程int類型),但是read(buf)返回的是讀取到的字節(jié)數(shù),真正的數(shù)據(jù)保存在buf中 while ((hasRead = fis.read(buf)) > 0) { //每次最多將1024個(gè)字節(jié)轉(zhuǎn)換成字符串,這里tmp2.txt中的字符小于1024,所以一次就讀完了 //循環(huán)次數(shù) = 文件字符數(shù) 除以 buf長(zhǎng)度 System.out.println(new String(buf, 0 ,hasRead)); /* * 將字節(jié)強(qiáng)制轉(zhuǎn)換成字符后逐個(gè)輸出,能實(shí)現(xiàn)和上面一樣的效果。但是如果源文件是中文的話可能會(huì)亂碼 for (byte b : buf) { char ch = (char)b; if (ch != '\r') System.out.print(ch); } */ } //在finally塊里close更安全 fis.close(); } public static void FileReaderTest() throws IOException { try ( // 在try() 中打開的文件, JVM會(huì)自動(dòng)關(guān)閉 FileReader fr = new FileReader("tmp2.txt")) { char[] buf = new char[32]; int hasRead = 0; // 每個(gè)char都占兩個(gè)字節(jié),每個(gè)字符或者漢字都是占2個(gè)字節(jié),因此無(wú)論buf長(zhǎng)度為多少,總是能讀取中文字符長(zhǎng)度的整數(shù)倍,不會(huì)亂碼 while ((hasRead = fr.read(buf)) > 0) { // 如果buf的長(zhǎng)度大于文件每行的長(zhǎng)度,就可以完整輸出每行,否則會(huì)斷行。 // 循環(huán)次數(shù) = 文件字符數(shù) 除以 buf長(zhǎng)度 System.out.println(new String(buf, 0, hasRead)); // 跟上面效果一樣 // System.out.println(buf); } } catch (IOException ex) { ex.printStackTrace(); } } public static void FileOutputStreamTest() throws FileNotFoundException, IOException { try ( //在try()中打開文件會(huì)在結(jié)尾自動(dòng)關(guān)閉 FileInputStream fis = new FileInputStream("tmp2.txt"); FileOutputStream fos = new FileOutputStream("tmp3.txt"); ) { byte[] buf = new byte[4]; int hasRead = 0; while ((hasRead = fis.read(buf)) > 0) { //每讀取一次就寫一次,讀多少就寫多少 fos.write(buf, 0, hasRead); } System.out.println("write success"); } catch (IOException e) { e.printStackTrace(); } } public static void FileWriterTest() throws IOException { try (FileWriter fw = new FileWriter("tmp4.txt")) { fw.write("天王蓋地虎\r\n"); fw.write("寶塔鎮(zhèn)河妖\r\n"); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) throws IOException { //FileInputStreamTest(); //FileReaderTest(); //FileOutputStreamTest(); FileWriterTest(); } }
包裝流:PrintStream/PrintWriter/Scanner
PrintStream可以封裝(包裝)直接與文件交互的節(jié)點(diǎn)流對(duì)象OutputStream, 使得編程人員可以忽略設(shè)備底層的差異,進(jìn)行一致的IO操作。因此這種流也稱為處理流或者包裝流。
PrintWriter除了可以包裝字節(jié)流OutputStream之外,還能包裝字符流Writer
Scanner可以包裝鍵盤輸入,方便地將鍵盤輸入的內(nèi)容轉(zhuǎn)換成我們想要的數(shù)據(jù)類型。
字符串流:StringReader/StringWriter
這兩個(gè)操作的是專門操作String字符串的流,其中StringReader能從String中方便地讀取數(shù)據(jù)并保存到char數(shù)組,而StringWriter則將字符串類型的數(shù)據(jù)寫入到StringBuffer中(因?yàn)镾tring不可寫)。
轉(zhuǎn)換流:InputStreamReader/OutputStreamReader
這兩個(gè)類可以將字節(jié)流轉(zhuǎn)換成字符流,被稱為字節(jié)流與字符流之間的橋梁。我們經(jīng)常在讀取鍵盤輸入(System.in)或網(wǎng)絡(luò)通信的時(shí)候,需要使用這兩個(gè)類
緩沖流:BufferedReader/BufferedWriter , BufferedInputStream/BufferedOutputStream
Oracle官方的描述:
Most of the examples we've seen so far use unbuffered I/O. This means each read or write request is handled directly by the underlying OS. This can make a program much less efficient.
Buffered input streams read data from a memory area known as a buffer; the native input API is called only when the buffer is empty. Similarly, buffered output streams write data to a buffer, and the native output API is called only when the buffer is full.
即,
沒有經(jīng)過Buffered處理的IO, 意味著每一次讀和寫的請(qǐng)求都會(huì)由OS底層直接處理,這會(huì)導(dǎo)致非常低效的問題。
經(jīng)過Buffered處理過的輸入流將會(huì)從一個(gè)buffer內(nèi)存區(qū)域讀取數(shù)據(jù),本地API只會(huì)在buffer空了之后才會(huì)被調(diào)用(可能一次調(diào)用會(huì)填充很多數(shù)據(jù)進(jìn)buffer)。
經(jīng)過Buffered處理過的輸出流將會(huì)把數(shù)據(jù)寫入到buffer中,本地API只會(huì)在buffer滿了之后才會(huì)被調(diào)用。
BufferedReader/BufferedWriter可以將字符流(Reader)包裝成緩沖流,這是最常見用的做法。
另外,BufferedReader提供一個(gè)readLine()可以方便地讀取一行,而FileInputStream和FileReader只能讀取一個(gè)字節(jié)或者一個(gè)字符,
因此BufferedReader也被稱為行讀取器
package io; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.PushbackReader; import java.io.StringReader; import java.io.StringWriter; public class TestIO { public static void printStream() throws FileNotFoundException, IOException { try ( FileOutputStream fos = new FileOutputStream("tmp.txt"); PrintStream ps = new PrintStream(fos)) { ps.println("普通字符串\n"); //輸出對(duì)象 ps.println(new TestIO()); } catch (IOException e) { e.printStackTrace(); } System.out.println("輸出完成"); } public static void stringNode() throws IOException { String str = "天王蓋地虎\n" + "寶塔鎮(zhèn)河妖\n"; char[] buf = new char[32]; int hasRead = 0; //StringReader將以String字符串為節(jié)點(diǎn)讀取數(shù)據(jù) try (StringReader sr = new StringReader(str)) { while ((hasRead = sr.read(buf)) > 0) { System.out.print(new String(buf, 0, hasRead)); } } catch (IOException e) { e.printStackTrace(); } //由于String是一個(gè)不可變類,因此創(chuàng)建StringWriter時(shí),實(shí)際上是以一個(gè)StringBuffer作為輸出節(jié)點(diǎn) try (StringWriter sw = new StringWriter()) { sw.write("黑夜給了我黑色的眼睛\n"); sw.write("我卻用它尋找光明\n"); //toString()返回sw節(jié)點(diǎn)內(nèi)的數(shù)據(jù) System.out.println(sw.toString()); } catch (IOException e) { e.printStackTrace(); } } public static void keyIn() throws IOException { try ( //InputStreamReader是從byte轉(zhuǎn)成char的橋梁 InputStreamReader reader = new InputStreamReader(System.in); //BufferedReader(Reader in)是char類型輸入的包裝類 BufferedReader br = new BufferedReader(reader); ) { String line = null; while ((line = br.readLine()) != null) { if (line.equals("exit")) { //System.exit(1); break; } System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } public static void pushback() throws FileNotFoundException, IOException { try (PushbackReader pr = new PushbackReader(new FileReader("C:/PROJECT/JavaBasic/PROJECT_JavaBasic/src/io/TestIO.java"),64)) { char[] buf = new char[32]; String lastContent = ""; int hasRead = 0; while ((hasRead = pr.read(buf)) > 0) { String content = new String(buf, 0, hasRead); int targetIndex = 0; if ((targetIndex = (lastContent + content).indexOf("targetIndex = (lastContent + content)")) > 0) { pr.unread((lastContent + content).toCharArray()); if (targetIndex > 32) { buf = new char[targetIndex]; } pr.read(buf , 0 , targetIndex); System.out.println(new String(buf, 0 , targetIndex)); System.exit(0); } else { System.out.println(lastContent); lastContent = content; } } } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) throws IOException { printStream(); //stringNode(); //keyIn(); //pushback(); } }
總結(jié)上面幾種流的應(yīng)用場(chǎng)景:
FileInputStream/FileOutputStream 需要逐個(gè)字節(jié)處理原始二進(jìn)制流的時(shí)候使用,效率低下
FileReader/FileWriter 需要組個(gè)字符處理的時(shí)候使用
StringReader/StringWriter 需要處理字符串的時(shí)候,可以將字符串保存為字符數(shù)組
PrintStream/PrintWriter 用來(lái)包裝FileOutputStream 對(duì)象,方便直接將String字符串寫入文件
Scanner 用來(lái)包裝System.in流,很方便地將輸入的String字符串轉(zhuǎn)換成需要的數(shù)據(jù)類型
InputStreamReader/OutputStreamReader , 字節(jié)和字符的轉(zhuǎn)換橋梁,在網(wǎng)絡(luò)通信或者處理鍵盤輸入的時(shí)候用
BufferedReader/BufferedWriter , BufferedInputStream/BufferedOutputStream , 緩沖流用來(lái)包裝字節(jié)流后者字符流,提升IO性能,BufferedReader還可以方便地讀取一行,簡(jiǎn)化編程。
以上就是JAVA IO體系是怎樣的,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。