大多數應用程序都須要實現與設備之間的數據傳輸,例如鍵盤能夠輸入數據,顯示器能夠顯示程序的運行結果等。在Java中,將這種經過不一樣輸入輸出設備(鍵盤,內存,顯示器,網絡等)之間的數據傳輸抽象表述爲」流」,程序容許經過流的方式與輸入輸出設備進行數據傳輸。Java中的」流」都位於java.io包中,稱爲IO(輸入輸出)流。java
IO流四你們族:數組
其中一、2統稱字節流,三、4統稱字符流。接下來就來詳細介紹這四你們族流的用法。網絡
在計算機中,不管是文本、圖片、音頻、仍是視頻,全部的文件都是以二進制(字節)形式存在,IO流中針對字節的輸入輸出提供了一系列的流,統稱爲字節流。字節流是程序中最經常使用的流,根據數據的傳輸方向可將其分爲字節輸入流和字節輸出流。在JDK中,提供了兩個抽象類InputStream和OutputStream,它們是字節流的頂級父類,全部的字節輸入流都繼承自InputStream,全部的字節輸出流都繼承自OutputStream。學習
注意:以上所說的全部」輸入」、」輸出」都是相對於程序而言。數據經過輸入流從源設備輸入到程序,經過輸出流從程序輸出到目標設備,從而實現數據的傳輸。spa
經常使用方法:操作系統
前三個read()方法都是用來讀數據的,其中,第一個read()方法是從輸入流中逐個讀入字節,而第二個和第三個read()方法則將若干字節以字節數組的形式一次性讀入,從而提升讀數據的效率。在進行IO流操做時,當前IO流會佔用必定的內存,因爲系統資源寶貴,所以,在IO流操做結束後,應該調用close()方法關閉流,從而釋放當前IO流所佔的系統資源。視頻
Demo:讀取文件text.txt中的內容對象
1 2 3 4 5 6 7 8 9 10 11 12 |
import java.io.*; public class Example{ public static void main(String[] args){ FileInputStream in=new FileInputStream("text.txt"); int b;//定義一個int類型的變量,記住每次讀取的一個字節。 while((b=in.read())!=-1) { System.out.prinln(b);//逐個打印出讀取的每個字節 } in.close(); } } |
經常使用方法:繼承
前三個是重載的write()方法,都是用於向輸出流寫入字節,其中,第一個方法逐個寫入字節,後兩個方法是將若干個字節以字節數組的形式一次性寫入,從而提升寫數據的效率。flush()方法用來將當前輸出流緩衝區(一般是字節數組)中的數據強制寫入目標設備,此過程稱爲刷新。close()方法是用來關閉流並釋放與當前IO流相關的系統資源。圖片
Demo:將字符串(首先要將字符串轉換爲字節)寫入到文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.io.*; public class Example{ public static void main(String[] args){ FileOutputStream out=new FileOutputStream(目標文件的路徑); String str="hello world"; byte[] b=str.getBytes();//字符串調用getBytes()方法便可轉換成字節數組。 for(int i=0;i<b.length;i++) { out.write(b[i]); } out.close(); } } |
InputStream和OutputStream這兩個類雖然提供了一系列和讀寫數據有關的方法,可是這兩個類都是抽象類,不能被實例化。所以,針對不一樣的功能,兩者提供了不一樣的子類。
下面這個例子經過對文件的複製來說解InputStream和OutputStream的用法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import java.io.*; public class Example{ public static void main(String[] args){ String fileName="/Users/codingBoy/Desktop/example1.jpg";//源文件路徑 String fileName2="/Users/codingBoy/Desktop/example2.jpg";//目標文件路徑 InputStream in=null; OutputStream out=null; try { in = new FileInputStream(fileName); out = new FileOutputStream(fileName2); int b; while ((b = in.read())!= -1) { out.write(b); } }catch (Exception e) { throw new RuntimeException(e); }finally { try { if (in != null) in.close(); if (out!=null) out.close(); }catch (Exception e) { throw new RuntimeException(e); } } } } |
上面的例子實現了對文件的複製,可是一個字節一個字節的讀寫,須要頻繁的操做文件,效率很是低。爲了提升效率,須要使用兩個帶緩衝的字節流,分別是BufferedInputStream和BufferedOutputStream,它們兩個同時也屬於上文JavaWeb學習筆記之Jdbc二中講到的裝飾流。下面經過增長字節緩衝流來對上述例子進行變更:
Demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import java.io.*; public class Example{ public static void main(String[] args){ String fileName="/Users/codingBoy/Desktop/example1.jpg";//源文件路徑 String fileName2="/Users/codingBoy/Desktop/example2.jpg";//目標文件路徑 InputStream in=null; OutputStream out=null; BufferedInputStream bis=null; BufferedOutputStream bos=null; try { in = new FileInputStream(fileName); bis = new BufferedInputStream(in);//將輸入流對象做爲參數傳遞給輸入緩衝流 out = new FileOutputStream(fileName2); bos = new BufferedOutputStream(out); int len; while((len=bis.read())!=-1) { bos.write(len); } catch (Exception e) { throw new RuntimeException(e); }finally { try { if (in != null) in.close(); if (bis!=null) bis.close(); if (out!=null) out.close(); if (bos!=null) bos.close(); }catch (Exception e) { throw new RuntimeException(e); } } } } |
前面咱們講過的InputStream和OutputStream類在讀寫文件時操做的都是字節,若是但願在程序中操做字符,使用這兩個類就不太方便,爲此JDK提供了字符流。同字節流同樣,字符流也有兩個抽象的頂級父類,分別是Reader和Writer。其中Reader是字符輸入流,用於從某個源設備讀取字符,Writer是字符輸出流,用於向某個目標設備寫入字符。其API跟字節流的相似。
Demo:讀取reader.txt中的字符串
1 2 3 4 5 6 7 8 9 10 11 12 |
import java.io.*; public class Example{ public static void main(String[] args){ FileReader reader=new FileReader("reader.txt"); int ch; while((ch=reader.read())!=-1) { System.out.println((char)ch);//經過read()方法讀取到的是int類型的值,因此須要進行強制轉換。 } reader.close(); } } |
Demo:將字符串輸出到目標文件中
1 2 3 4 5 6 7 8 9 10 |
import java.io.*; public class Example{ public static void main(String[] args){ FileWrite out=new FileWrite(目標文件的路徑); String str="hello world"; out.write(str); out.close(); } } |
字符流一樣提供了帶緩衝區的包裝流,分別是BufferedWriter和BufferedReader,其中BufferedReader用於對字符輸入流的包裝,BufferedWriter用於對字符輸出流的包裝。須要注意的是,在BufferedReader中有一個重要的方法readLine(),該方法用於一次讀取一行文本。接下來經過一個例子學習如何使用這兩個包裝流實現文件的複製。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import java.io.*; public class Example{ public static void main(String[] args){ String fileName="/Users/codingBoy/Desktop/example1.jpg";//源文件路徑 String fileName2="/Users/codingBoy/Desktop/example2.jpg";//目標文件路徑 Reader reader=null; BufferedReader bf=null; Writer writer=null; BufferedWriter bw=null; try { reader = new Reader(fileName); br=new BufferedReader(reader); writer = new Writer(fileName2); bw=new BufferedWriter(writer); String str; while ((str = bf.readLine())!= null) { bw.write(str); bw.newLine();//寫入一個換行符,該方法會根據不一樣的操做系統生成相應的換行符。 } }catch (Exception e) { throw new RuntimeException(e); }finally { try { if (reader != null) reader.close(); if (br !=null) br.close(); if (writer!=null) writer.close(); if (bw !=null) bw.close(); }catch (Exception e) { throw new RuntimeException(e); } } } } |
前面提到IO流可分爲字節流和字符流,有時字節流和字符流之間也須要進行轉換。在JDK中提供了兩個類能夠將字節流轉換爲字符流,它們分別是InputStreamReader和OutputStreamWriter。
轉換流也是一種包裝流,其中OutputStreamWriter是Writer的子類,它能夠將一個字節輸出流包裝成字符輸出流,方便直接寫入字符,而InputStreamReader是Reader的子類,它能夠將一個字節輸入流包裝成字符輸入流,方便直接讀取字符。
Demo:將字節流轉換爲字符流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import java.io.*; public class Example{ public static void main(String[] args){ String fileName="/Users/codingBoy/Desktop/example1.jpg";//源文件路徑 String fileName2="/Users/codingBoy/Desktop/example2.jpg";//目標文件路徑 InputStreamReader isr=new InputStreamReader(new FileInputStream(fileName1)); BufferedReader br=new BufferedReader(isr); OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream(fileName2)); BufferedWriter bw=new BufferedWriter(osw); String line; while((line=br.readLine())!=null) { bw.write(line); } br.close(); bw.close(); } } |
在前面的學習中,都是將文件直接存儲到硬盤,但有時候咱們但願將文件臨時存儲到緩衝區,方便之後讀取。爲此JDK中提供了一個ByteArrayOutputStream類。該類會在建立對象時就建立一個byte型數組的緩衝區,當向數組中寫數據時,該對象會把全部的數據先寫入緩衝區,最後一次行寫入文件。
Demo:將數據寫入緩衝區
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import java.io.*; public class Example{ public static void main(String[] args){ String fileName1="/Users/codingBoy/Desktop/example1.jpg";//源文件路徑 String fileName2="/Users/codingBoy/Desktop/example2.jpg";//目標文件路徑 FileInputStream in=new FileInputStream(fileName1); ByteArrayOutputStream bos=new ByteArrayOutputStream(); FileOutputStream out=new FileOutputStream(fileName2); int b; while((b=in.read())!=-1) { bos.write(b);//先將數據寫入緩衝區,當須要寫入目標文件中的時候再調用輸出流的write(bos.toByteArray())方法。 } in.close(); bos.close(); out.write(bos.toByteArray()); out.close(); } |
在該例中,定義了一個ByteArrayOutputStream對象,將從fileName1文件中讀取的字節所有寫入該對象的緩衝區,經過FileOutputStream對象將緩衝區的數據一次性寫入fileName2文件。
與ByteArrayOutputStream相似,ByteArrayInputStream是從緩衝區中讀取數據,接下來經過一個案例來演示ByteArrayInputStream如何讀取緩衝區的數據。
Demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.io.*; public class Example{ public static void main(String[] args){ byte[] bytes=new byte[]{97,98,99,100}; ByteArrayInputStream bis=new ByteArrayInputStream(bytes); int b; while((b=bis.read())!=-1) { System.out.println((char)b); } } |