1.流的概念
Java采用流的機制來實現輸入/輸出。
流是一個很形象的概念,當程序需要讀取數據的時候,就會開啟一個通向數據源的流,這個數據源可以是文件,內存,或是網絡連接。類似的,當程序需要寫入數據的時候,就會開啟一個通向目的地的流。這時候你就可以想象數據好像在這其中“流”動一樣,如下圖:
輸出流:

輸入流:






InputStream:輸入字節流。繼承自InputStream的流都是用于向程序中輸入數據的,且數據單位都是字節(8位 byte[])。
InputStream 是所有的輸入字節流的父類,它是一個抽象類。
ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三種基本的介質流,它們分別從Byte 數組、StringBuffer、和本地文件中讀取數據。PipedInputStream 是從與其它線程共用的管道中讀取數據。
ObjectInputStream 和所有FilterInputStream 的子類都是裝飾流(裝飾器模式的主角)。
Inputstream類中的常用方法:
(1) public abstract int read( ):讀取一個byte的數據,返回值是高位補0的int類型值。若返回值=-1說明沒有讀取到任何字節讀取工作結束。
(2) public int read(byte b[ ]):讀取b.length個字節的數據放到b數組中。返回值是讀取的字節數。該方法實際上是調用下一個方法實現的
(3) public int read(byte b[ ], int off, int len):從輸入流中最多讀取len個字節的數據,存放到偏移量為off的b數組中。
(4) public int available( ):返回輸入流中可以讀取的字節數。注意:若輸入阻塞,當前線程將被掛起,如果InputStream對象調用這個方法的話,它只會返回0,這個方法必須由繼承InputStream類的子類對象調用才有用,
(5) public long skip(long n):忽略輸入流中的n個字節,返回值是實際忽略的字節數, 跳過一些字節來讀取
(6) public int close( ) :我們在使用完后,必須對我們打開的流進行關閉.
OutputSteam:輸出字節流。繼承自OutputStream的流都是程序用于向外輸出數據的,且數據單位都是字節(8位 byte[])。
OutputStream 是所有的輸出字節流的父類,它是一個抽象類。
ByteArrayOutputStream、FileOutputStream 是兩種基本的介質流,它們分別向Byte 數組、和本地文件中寫入數據。PipedOutputStream 是向與其它線程共用的管道中寫入數據,
ObjectOutputStream 和所有FilterOutputStream 的子類都是裝飾流。
OutputSteam類中的常用方法:
(1) public void write(byte b[ ]):將參數b中的字節寫到輸出流。
(2) public void write(byte b[ ], int off, int len) :將參數b的從偏移量off開始的len個字節寫到輸出流。
(3) public abstract void write(int b) :先將int轉換為byte類型,把低字節寫入到輸出流中。
(4) public void flush( ) : 將數據緩沖區中數據全部輸出,并清空緩沖區。
(5) public void close( ) : 關閉輸出流并釋放與流相關的系統資源。
Reader:輸入字符流。繼承自Reader的流都是用于向程序中輸入數據的,且數據單位都是字符(16位 char[])。
Reader 是所有的輸入字符流的父類,它是一個抽象類。
CharReader、StringReader 是兩種基本的介質流,它們分別將Char 數組、String中讀取數據。PipedReader 是從與其它線程共用的管道中讀取數據。
BufferedReader 很明顯就是一個裝飾器,它和其子類負責裝飾其它Reader 對象。
FilterReader 是所有自定義具體裝飾流的父類,其子類PushbackReader 對Reader 對象進行裝飾,會增加一個行號。
InputStreamReader 是一個連接字節流和字符流的橋梁,它將字節流轉變為字符流。FileReader 可以說是一個達到此功能、常用的工具類,在其源代碼中明顯使用了將FileInputStream 轉變為Reader 的方法。我們可以從這個類中得到一定的技巧。Reader 中各個類的用途和使用方法基本和InputStream 中的類使用一致。
Reader類中的常用方法:
(1) public int read() throws IOException; //讀取一個字符,返回值為讀取的字符
(2) public int read(char cbuf[]) throws IOException; /*讀取一系列字符到數組cbuf[]中,返回值為實際讀取的字符的數量*/
(3) public abstract int read(char cbuf[],int off,int len) throws IOException; /*讀取len個字符,從數組cbuf[]的下標off處開始存放,返回值為實際讀取的字符數量,該方法必須由子類實現*/
Writer:輸出字符流。繼承自Writer的流都是程序用于向外輸出數據的,且數據單位都是字符(16位 char[])。
Writer 是所有的輸出字符流的父類,它是一個抽象類。
CharArrayWriter、StringWriter 是兩種基本的介質流,它們分別向Char 數組、String 中寫入數據。PipedWriter 是向與其它線程共用的管道中寫入數據,
BufferedWriter 是一個裝飾器為Writer 提供緩沖功能。
PRintWriter 和PrintStream 極其類似,功能和使用也非常相似。
OutputStreamWriter 是OutputStream 到Writer 轉換的橋梁,它的子類FileWriter 其實就是一個實現此功能的具體類。
Writer類中的常用方法:
(1) public void write(int c) throws IOException; //將整型值c的低16位寫入輸出流
(2) public void write(char cbuf[]) throws IOException; //將字符數組cbuf[]寫入輸出流
(3) public abstract void write(char cbuf[],int off,int len) throws IOException; //將字符數組cbuf[]中的從索引為off的位置處開始的len個字符寫入輸出流
(4) public void write(String str) throws IOException; //將字符串str中的字符寫入輸出流
(5) public void write(String str,int off,int len) throws IOException; //將字符串str 中從索引off開始處的len個字符寫入輸出流
(6) flush( ) //刷空輸出流,并輸出所有被緩存的字節。
(7) close() 關閉流 public abstract void close() throws IOException
Java輸入輸出流有兩個對稱性
輸入-輸出對稱: InputStream和OutputStream各自在Byte流輸入和輸出的兩個平行結構的等級的根部;Reader和Writer各自在Char流輸入和輸出的兩個平行結構的根部
byte-char對稱:InputStream和Reader的子類分別負責Byte和Char流的輸入;OutputStream和Writer的子類分別負責Byte和Char流的輸出。分別形成平行的等級結構。
1.字節流中原始流的代表:FileInputStream FileOutputStream
FileInputStream 從一個文件中讀取byte[]
FileOutputStream 將byte[]寫入到一個文件中
FileInputStream/FileOutputStream的例子
具體的內容是:從利用FileInputStream從input.txt中讀出byte流,用某種編碼格式轉換為String顯示出來,然后將String轉換成byte流,利用FileOutputStream將byte流寫入到output.txt中

1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.nio.ByteBuffer; 7 import java.nio.charset.Charset; 8 9 public class FileStreamDemo {10 public static void main(String[] args) {11 try {12 FileInputStream fis = new FileInputStream(new File("input.txt"));13 byte[] bis = new byte[fis.available()];14 fis.read(bis);15 fis.close();16 /*17 * 關于byte[]轉換為String編碼配置有兩種方法,建議使用第二種方案 1.String str = new18 * String(b,"charsetname") 2.Charset charset = =19 * Charset.forName("charsetname"); String str =20 * charset.decode(ByteBuffer.wrap(b)).toString();21 */22 Charset charset = Charset.forName("UTF-8");23 String str = charset.decode(ByteBuffer.wrap(bis)).toString();24 // String str = new String(bis);25 // //byte轉換為String,默認的編碼是"ISO-8859-1",即根據編輯器的編碼來確定編碼方式26 System.out.println(str);27 28 FileOutputStream fos = new FileOutputStream(new File("output.txt"));29 byte[] bos = str.getBytes();30 fos.write(bos);31 fos.close();32 33 } catch (FileNotFoundException e) {34 // TODO Auto-generated catch block35 e.printStackTrace();36 } catch (IOException e) {37 // TODO Auto-generated catch block38 e.printStackTrace();39 }40 41 }42 }FileStreamDemo.java2.字節流中裝飾流之BufferInputStream BufferOutputStream
BufferInputStream:將原始InputStream中的byte[]讀到內存緩存區中,然后從緩沖區讀取byte[]
BufferOutputStream:向一個緩沖區中寫入byte[],將緩沖區中的byte[]寫入到原始outputStream中
BufferInputStream和BufferoutputStream對原始輸入輸出流進行裝飾,使得流的讀/寫操作使用緩沖機制,這樣不會對每次的流讀/寫操作都產生一個物理的讀/寫操作,從而提高了程序的效率。涉及物理流的地方,如控制臺I/O,文件I/O等,都應當使用這個裝飾流處理器。
舉例:

1 import java.io.BufferedInputStream; 2 import java.io.BufferedOutputStream; 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 import java.nio.ByteBuffer; 9 import java.nio.charset.Charset;10 11 public class BufferStreamDemo {12 public static void main(String[] args) {13 try {14 15 FileInputStream fis = new FileInputStream(new File("input.txt"));16 BufferedInputStream bfis = new BufferedInputStream(fis);17 byte[] bis = new byte[bfis.available()];18 bfis.read(bis);19 bfis.close();20 fis.close();21 /*22 * 關于byte[]轉換為String編碼配置有兩種方法,建議使用第二種方案 1.String str = new23 * String(b,"charsetname") 2.Charset charset = =24 * Charset.forName("charsetname"); String str =25 * charset.decode(ByteBuffer.wrap(b)).toString();26 */27 Charset charset = Charset.forName("UTF-8");28 String str = charset.decode(ByteBuffer.wrap(bis)).toString();29 // String str = new String(bis);30 // //byte轉換為String,默認的編碼是"ISO-8859-1",即根據編輯器的編碼來確定編碼方式31 System.out.println(str);32 33 FileOutputStream fos = new FileOutputStream(new File("output.txt"));34 BufferedOutputStream bfos = new BufferedOutputStream(fos);35 byte[] bos = str.getBytes();36 bfos.write(bos);37 bfos.close();38 fos.close();39 } catch (FileNotFoundException e) {40 // TODO Auto-generated catch block41 e.printStackTrace();42 } catch (IOException e) {43 // TODO Auto-generated catch block44 e.printStackTrace();45 }46 47 }48 }BufferStreamDemo.java3.字節裝飾流之ObjectInputStream ObjectOutputStream
ObjectInputStream :對象輸入流,將使用ObjectOutputStream串行化的原始數據類型和對象重新并行化
ObjectOutputStream:對象輸出流,將原始數據類型和對象串行化
使用ObjectInputStream/ObjectOutputStream類所讀寫的對象必須實現Serializable接口,對象中的transient和static類型成員變量不會被讀取和寫入
舉例:

1 import java.io.BufferedInputStream; 2 import java.io.BufferedOutputStream; 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 import java.nio.ByteBuffer; 9 import java.nio.charset.Charset;10 11 public class BufferStreamDemo {12 public static void main(String[] args) {13 try {14 15 FileInputStream fis = new FileInputStream(new File("input.txt"));16 BufferedInputStream bfis = new BufferedInputStream(fis);17 byte[] bis = new byte[bfis.available()];18 bfis.read(bis);19 bfis.close();20 fis.close();21 /*22 * 關于byte[]轉換為String編碼配置有兩種方法,建議使用第二種方案 1.String str = new23 * String(b,"charsetname") 2.Charset charset = =24 * Charset.forName("charsetname"); String str =25 * charset.decode(ByteBuffer.wrap(b)).toString();26 */27 Charset charset = Charset.forName("UTF-8");28 String str = charset.decode(ByteBuffer.wrap(bis)).toString();29 // String str = new String(bis);30 // //byte轉換為String,默認的編碼是"ISO-8859-1",即根據編輯器的編碼來確定編碼方式31 System.out.println(str);32 33 FileOutputStream fos = new FileOutputStream(new File("output.txt"));34 BufferedOutputStream bfos = new BufferedOutputStream(fos);35 byte[] bos = str.getBytes();36 bfos.write(bos);37 bfos.close();38 fos.close();39 } catch (FileNotFoundException e) {40 // TODO Auto-generated catch block41 e.printStackTrace();42 } catch (IOException e) {43 // TODO Auto-generated catch block44 e.printStackTrace();45 }46 47 }48 }BufferStreamDemo.java
1 import java.io.*; 2 3 public class Student implements Serializable { 4 5 String name; 6 int id; 7 int age; 8 String department; 9 10 public Student(String name, int id, int age, String department) {11 this.age = age;12 this.department = department;13 this.id = id;14 this.name = name;15 }16 }Student.java4.字節裝飾流之DataInputStream DataOutputStream
DataInputStream:提供基于多字節的讀取方法,可以讀取原始數據類型的數據
DataOutputStream:提供基于多字節的寫出方法,可以寫出原始數據類型的數據
舉例:

1 public class Member { 2 private String name; 3 private int age; 4 5 public Member() { 6 } 7 8 public Member(String name, int age) { 9 this.name = name;10 this.age = age;11 }12 13 public void setName(String name) {14 this.name = name;15 }16 17 public void setAge(int age) {18 this.age = age;19 }20 21 public String getName() {22 return name;23 }24 25 public int getAge() {26 return age;27 }28 }Member.java
1 import java.io.*; 2 3 public class DataStreamDemo { 4 public static void main(String[] args) { 5 Member[] members = { new Member("Justin", 90), new Member("momor", 95), 6 new Member("Bush", 88) }; 7 try { 8 DataOutputStream dataOutputStream = new DataOutputStream( 9 new FileOutputStream(new File("file.txt")));10 11 for (Member member : members) {12 // 寫入UTF字符串13 dataOutputStream.writeUTF(member.getName());14 // 寫入int數據15 dataOutputStream.writeInt(member.getAge());16 }17 18 // 所有數據至目的地19 dataOutputStream.flush();20 // 關閉流21 dataOutputStream.close();22 23 DataInputStream dataInputStream = new DataInputStream(24 new FileInputStream(new File("file.txt")));25 26 // 讀出數據并還原為對象27 for (int i = 0; i < members.length; i++) {28 // 讀出UTF字符串29 String name = dataInputStream.readUTF();30 // 讀出int數據31 int score = dataInputStream.readInt();32 members[i] = new Member(name, score);33 }34 35 // 關閉流36 dataInputStream.close();37 38 // 顯示還原后的數據39 for (Member member : members) {40 System.out41 .printf("%s/t%d%n", member.getName(), member.getAge());42 }43 } catch (IOException e) {44 e.printStackTrace();45 }46 }47 }DataStreamDemo.java5.字符流之StringReader和StringWriter
StringReader:數據從String中讀取到char[]
StringWriter:將char[]寫入到String中
舉例:

1 import java.io.IOException; 2 import java.io.StringReader; 3 import java.io.StringWriter; 4 5 public class StringStreamTest { 6 public static void main(String[] args) { 7 String str = "abcdefghijklmn"; 8 transform(str); 9 }10 11 public static void transform(String str) {12 StringReader sr = new StringReader(str);13 StringWriter sw = new StringWriter();14 char[] chars = new char[1024];15 try {16 int len = 0;17 while ((len = sr.read(chars)) != -1) {18 String strRead = new String(chars, 0, len).toUpperCase();19 System.out.println(strRead);20 sw.write(strRead);21 sw.flush();22 }23 sr.close();24 sw.close();25 } catch (IOException e) {26 e.printStackTrace();27 } finally {28 sr.close();29 try {30 sw.close();31 } catch (IOException e) {32 e.printStackTrace();33 }34 }35 }36 }StringStreamTest.java6.字符裝飾流之 BufferedReader/BufferedWriter
BufferedReader/BufferedWriter的作用和BufferInputStream/BufferOutputStream類似,但BufferedReader提供了一個readline方法,可以將存儲的一行的char[]讀取出來
舉例:

1 import java.io.*; 2 3 class BufferReaderDemo { 4 public static void main(String arg[]) throws IOException { 5 BufferedReader b = new BufferedReader(new FileReader("c.txt")); 6 boolean c; 7 do { 8 String s = b.readLine(); 9 System.out.println(s);10 } while (c = b.read() != -1);11 }12 }BufferReaderDemo.java7.從byte流到char流的適配InputStreamReader和OutputStreamWriter
byte流到char流的適配是通過InputStreamReader和OutputStreamWriter來解決的
InputStreamReader:是字節流通向字符流的橋梁。你可以在構造器重指定編碼的方式,如果不指定的話將采用底層操作系統的默認編碼方式,例如 GBK 等
要啟用從字節到字符的有效轉換,可以提前從底層流讀取更多的字節,使其超過滿足當前讀取操作所需的字節。
為了達到最高效率,可要考慮在 BufferedReader 內包裝 InputStreamReader。例如:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
OutputStreamWriter :是字符流通向字節流的橋梁。每次調用 write() 方法都會導致在給定字符(或字符集)上調用編碼轉換器。在寫入底層輸出流之前,得到的這些字節將在緩沖區中累積
為了獲得最高效率,可考慮將 OutputStreamWriter 包裝到 BufferedWriter 中,以避免頻繁調用轉換器。例如:
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
舉例:

1 import java.io.BufferedReader; 2 import java.io.BufferedWriter; 3 import java.io.FileInputStream; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.io.InputStreamReader; 7 import java.io.OutputStreamWriter; 8 9 public class StreamReaderWriterDemo {10 public static void main(String[] args) {11 try {12 13 BufferedReader bufr = new BufferedReader(new InputStreamReader(14 new FileInputStream("f://01.txt")));15 16 BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(17 new FileOutputStream("f://02.txt")));18 19 int ch = 0;20 21 // 以字符方式顯示文件內容22 while ((ch = bufr.read()) != -1) {23 System.out.print((char) ch);24 bufw.write(ch);25 }26 if (bufr != null)27 bufr.close();28 if (bufw != null)29 bufw.close();30 } catch (ArrayIndexOutOfBoundsException e) {31 e.printStackTrace();32 } catch (IOException e) {33 e.printStackTrace();34 }35 }36 }StreamReaderWriterDemo.java8.InputStreamReader和OutputStreamWriter的子類:FileReader 和FileWriter
FileReader:文件字節流通向字符流的橋梁
FileWriter:是字符流通向文件字節流的橋梁。
舉例:

1 import java.io.BufferedReader; 2 import java.io.BufferedWriter; 3 import java.io.FileReader; 4 import java.io.FileWriter; 5 import java.io.IOException; 6 7 public class TestWriter { 8 // 功能:讀取E:/Test.txt文件的內容(一行一行讀),并將其內容寫入E:/Jack.txt中 9 // 知識點:java讀文件、寫文件---<以字符流方式>10 public static void main(String[] args) {11 try {12 // 創建FileReader對象,用來讀取字符流13 FileReader fr = new FileReader("E:/Test.txt");14 // 緩沖指定文件的輸入15 BufferedReader br = new BufferedReader(fr);16 // 創建FileWriter對象,用來寫入字符流17 FileWriter fw = new FileWriter("E:/Jack.txt");18 // 將緩沖對文件的輸出19 BufferedWriter bw = new BufferedWriter(fw);20 // 定義一個String類型的變量,用來每次讀取一行21 String myreadline;22 while (br.ready()) {23 // 讀取一行24 myreadline = br.readLine();25 // 寫入文件26 bw.write(myreadline);27 bw.newLine();28 // 在屏幕上輸出29 System.out.println(myreadline);30 }31 // 刷新該流的緩沖32 bw.flush();33 bw.close();34 br.close();35 fw.close();36 br.close();37 fr.close();38 39 } catch (IOException e) {40 e.printStackTrace();41 }42 }43 }TestWriter.java9.PrintStream OutputStream
PrintStream在OutputStream基礎之上提供了增強的功能,即可以方便地輸出各種類型的數據(而不僅限于byte型)的格式化表示形式。PrintStream的方法從不拋出IOException。
System.out是PrintStream的實例(注意System.in是一個BufferInputStream)
下面是一個Socket實例,使用了PrintStream System.out System.in

1 package zyb.org.client; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.PrintStream; 7 import java.net.Socket; 8 import java.net.SocketTimeoutException; 9 10 public class Client1 {11 public static void main(String[] args) throws IOException {12 //客戶端請求與本機在20006端口建立TCP連接 13 Socket client = new Socket("127.0.0.1", 20006);14 client.setSoTimeout(10000);15 //獲取鍵盤輸入 16 BufferedReader input = new BufferedReader(new InputStreamReader(System.in));17 //獲取Socket的輸出流,用來發送數據到服務端 18 PrintStream out = new PrintStream(client.getOutputStream());19 //獲取Socket的輸入流,用來接收從服務端發送過來的數據 20 BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream()));21 boolean flag = true;22 while(flag){23 System.out.print("輸入信息:");24 String str = input.readLine();25 //發送數據到服務端 26 out.println(str);27 if("bye".equals(str)){28 flag = false;29 }else{30 try{31 //從服務器端接收數據有個時間限制(系統自設,也可以自己設置),超過了這個時間,便會拋出該異常32 String echo = buf.readLine();33 System.out.println(echo);34 }catch(SocketTimeoutException e){35 System.out.println("Time out, No response");36 }37 }38 }39 input.close();40 if(client != null){41 //如果構造函數建立起了連接,則關閉套接字,如果沒有建立起連接,自然不用關閉42 client.close(); //只關閉socket,其關聯的輸入輸出流也會被關閉43 }44 }45 }Socket示例參考文章:
Java輸入輸出流詳解 http://blog.csdn.net/zsw12013/article/details/6534619
Java IO流分析整理 http://www.th7.cn/Program/java/201406/214540.shtml
Java輸入輸出流 http://blog.csdn.net/hguisu/article/details/7418161
《Java與模式》第27章 專題:設計模式在Java I/O庫中的應用
ObjectInputStream與ObjectOutputStream類http://blog.sina.com.cn/s/blog_77cb34170100r5o6.html
使用StringReader和StringWriter操作字符串http://blog.csdn.net/zhuhezan/article/details/6526915
InputStreamReader和OutputStreamWriter的用法http://blog.csdn.net/z69183787/article/details/8179889
Java FileReader FileWriter 示例 http://blog.163.com/jackswu@yeah/blog/static/1406291232011076011170/
printStream 和printWriter區別 http://blog.csdn.net/y3wegy/article/details/8783314
【Java TCP/IP Socket】TCP Socket(含代碼)http://blog.csdn.net/ns_code/article/details/14105457
新聞熱點
疑難解答