1、總的4類
字元:Reader 和Writer
位元組:InputStream和OutputStream
2、Reader
六個子類BufferedReader,CharArrayReader,FilterReader,InputStreamReader,PipedReader,StringReader
2.1 BufferedReader
為什麼用它?
將緩衝指定檔案的輸入。如果沒有緩衝,則每次調用 read() 或 readLine() 都會導致從檔案中讀取位元組,並將其轉換為字元後返回,而這是極其低效的
工作原理?
從字元輸入資料流中讀取文本,緩衝各個字元,從而實現字元、數組和行的高效讀取。
什麼時候用?
建議用 BufferedReader 封裝所有其 read() 操作可能開銷很高的 Reader(如 FileReader 和 InputStreamReader)
InputStreamReader又封裝System.in
將控制台輸入,賦給字串
BufferedReader buf = new BufferedReader( new InputStreamReader(System.in)); String str = null; System.out.println("請輸入內容"); try{ str = buf.readLine(); }catch(IOException e){ e.printStackTrace(); } System.out.println("你輸入的內容是:" + str);
跟蹤行號的緩衝字元輸入資料流
2.2 CharArrayReader
把字元數組作為源的輸入資料流的實現
緩衝字元數組,讀取每個字元的時候
String strTmp = "abcdefghijklmnopqrstuvwxyz"; int intLen = strTmp.length(); char c[] = new char[intLen]; strTmp.getChars(0,intLen,c,0);
CharArrayReader input1 = new CharArrayReader(c); CharArrayReader input2 = new CharArrayReader(c,0,5);
int i; System.out.println("input1 is : "); while((i=input1.))!=-1){ System.out.print((char)i); } System.out.println(); System.out.println("input2 is : "); while((i=input2.read())!=-1){ System.out.print((char)i); }
2.3 FilterReader抽象類別
允許將字元推回到流的字元流
unread(char c) 回壓一個字元; unread(char c[]) 回壓數組 c 中全部字元
unread(char c[],offset,int n) 回壓 c 中從 offset 開始的 n 個字元
編譯原理的一個重要的組成部分叫做詞法分析器,就是我上面提到的scanner。對於詞法剖析器來說,輸入就是原始碼,輸出就是一個一個的Token(想不出來合適的詞),通常詞法分析器會一個字元一個字元讀取,然後將將這些字元根據一定的規則群組成token的序列。有些時候,scanner需要超前讀下一個字元才能判斷當前的token是否已經結束。例如,int abc=5;這樣一個語句,詞法分析器要讀到=這個字元的時候才能確定abc是一個id,而不是"abc=",這樣=已經從輸入資料流中讀出來了,但是=又不屬於當前的Token,所以要把這個=退回去,這時就要用到pushback。
2.4InputStreamReader
是位元組流通向字元流的橋樑
要啟用從位元組到字元的有效轉換,可以提前從底層流讀取更多的位元組,使其超過滿足當前讀取操作所需的位元組。
為了達到最高效率,可要考慮在 BufferedReader 內封裝 InputStreamReader。例如:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
用來讀取字元檔案的便捷類
樣本1:讀取字元檔案並寫到數組
路徑分隔字元:File.separator
String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); char[] ch=new char[100]; Reader read=new FileReader(f); int count=read.read(ch); read.close(); System.out.println("讀入的長度為:"+count); System.out.println("內容為"+new String(ch,0,count));
2.5 PipedReader
傳送的字元輸入資料流。
管道輸入輸出資料流類主要用於線程之間的通訊,不建議對這兩個對象嘗試使用單個線程,因為這樣可能死結線程。
樣本1:管道輸入輸出資料流類用於線程之間的通訊(讀管道中資料到字元數組,寫到管道中)
兩個線程
一個讀一個寫,都用到管道流,並返回管道流對象
主函數中得到輸入輸出對象
輸出對象與輸入對象打通管道 t1.connect(t2);
開啟各自線程 s.start(); r.start();
PipedInputStream,PipedOutputStream管道輸入輸出資料流類主要用於線程之間的通訊,不建議對這兩個對象嘗試使用單個線程,因為這樣可能死結線程。PipedReader,Pipedwriter字元輸入輸出資料流類和上面的類似import java.io.*;public class PipedStreamTest { public static void main(String[] args) { // TODO Auto-generated method stub Sender s=new Sender(); Reciever r=new Reciever(); PipedWriter t1=s.getWriter(); PipedReader t2=r.getReader(); try{ t1.connect(t2); } catch(Exception e) { e.printStackTrace(); } s.start(); r.start(); }}class Reciever extends Thread{ PipedReader in=new PipedReader(); public PipedReader getReader() { return in; } public void run() { char [] buf=new char[1024]; try{ int len=in.read(buf); System.out.println("the following messageid:"+'\n'+ new String(buf,0,len)); in.close(); } catch(Exception e) { e.printStackTrace(); } }}class Sender extends Thread{ private PipedWriter out=new PipedWriter(); public PipedWriter getWriter() { return out; } public void run() { String strInfo=new String("hello,how are you doing?"); try{ out.write(strInfo); out.close(); } catch(Exception e) { e.printStackTrace(); } }}
2.6StringReader
其源為一個字串的字元流。文本資訊當作記憶體中的字元一樣來處理
StringReader並不常用,因為通常情況下使用String更簡單一些。但是在一些需要Reader作為參數的情況下,就需要將String讀入到StringReader中來使用了
樣本1:統計單詞數
StreamTokenizer(reader);需要reader參數
檔案未結束:streamTokenizer.nextToken() != StreamTokenizer.TT_EOF
讀到單詞:streamTokenizer.ttype == StreamTokenizer.TT_WORD
public void countWordsInAString() {StreamTokenizer streamTokenizer = null;String stringToBeParsed = "The quick brown fox jumped over the lazy dog";StringReader reader = new StringReader(stringToBeParsed);int wordCount = 0;try {streamTokenizer = new StreamTokenizer(reader);while (streamTokenizer.nextToken() != StreamTokenizer.TT_EOF) {if (streamTokenizer.ttype == StreamTokenizer.TT_WORD)wordCount++;}System.out.println("Number of words in file: " + wordCount);} catch (FileNotFoundException ex) {ex.printStackTrace();} catch (IOException ex) {ex.printStackTrace();}}
3、Writer類
7個子類:BufferedWriter, CharArrayWriter, FilterWriter, OutputStreamWriter, PipedWriter, PrintWriter, StringWriter
PrintWriter可以格式化輸出;與PrintStream的區別就是可以自動重新整理緩衝
FilterWriter沒有子類了
其他的跟reader匹配著用,都差不多
3.1BufferedWriter
將文本寫入字元輸出資料流,緩衝各個字元,從而提供單個字元、數組和字串的高效寫入
File file = new File(filepath); 02 //file.deleteOnExit(); 03 file.createNewFile(); 04 05 BufferedWriter write = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file),"UTF-8")); 06 write.write("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"); 07 write.write("<locals>\n"); 08 09 10 write.write("\t</province>\n"); 11 System.out.println("===完成省份:"+pro.getValue()); 12 } 13 write.write("</locals>"); 14 System.out.println("全部完成。。。。。。。。"); 15 write.flush(); 16 write.close();
3.2CharArrayWriter
操作的都是字元數組
此類實現一個可用作 Writer 的字元緩衝區。緩衝區會隨向流中寫入資料而自動成長。可使用 toCharArray() 和 toString() 擷取資料。
//顯示字元內容 array = charArrayWriter.toCharArray();
//將字元數組內容存迴文件 CharArrayReader charArrayReader = new CharArrayReader(array); BufferedWriter bufWriter = new BufferedWriter( new FileWriter(file)); char[] tmp = new char[1]; while(charArrayReader.read(tmp)!=-1) { bufWriter.write(tmp); } charArrayReader.close(); bufWriter.flush(); bufWriter.close();
3.3FilterWriter
沒啥用
3.4OutputStreamWriter
是字元流通向位元組流的橋樑
為了獲得最高效率,可考慮將 OutputStreamWriter 封裝到 BufferedWriter 中,以避免頻繁調用轉換器。例如:
Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
File f = new File("d:" + File.separator + "test.txt"); Writer out = null; out = new OutputStreamWriter(new FileOutputStream(f));// 位元組流變為字元流 out.write("hello world"); // 使用字元流輸出 out.close();
3.5PipedWriter
見2.5PipedReader
3.6PrintWriter
向文本輸出資料流列印對象的格式化表示形式
是一種過濾流,也叫處理流。也就是能對位元組流和字元流進行處理
可以對下面幾種輸出資料流格式化字串輸出
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("IODemo.out")));
首先,建立一個與指定檔案串連的FileWriter。實際上,我們通常會用BufferedWriter將起封裝起來用以緩衝輸出(......這裡面的我省略了)。然後為了格式化把它轉換成PrintWriter。
3.7StringWriter
一個字元流,可以用其回收在字串緩衝區中的輸出來構造字串。文本資訊當作記憶體中的字元一樣來處理
關閉 StringWriter 無效。此類中的方法在關閉該流後仍可被調用,而不會產生任何 IOException
StringWriter還有一個特點,那就是它能通過GetStringBuilder()方法來擷取一個System.Text.StringBuilder對象:
StringWriter strWriter = new StringWriter();...StringBuilder sb = strWriter.GetStringBuilder();sb.Insert(0, "Hey!! ");Console.WriteLine("-> {0}", sb.ToString());sb.Remove(0, "Hey!! ".Length);
StringWriter strWriter = new StringWriter();strWriter.WriteLine("Don't forget Mother's Day this year...");strWriter.Close();
4、InputStream
9個子類:AudioInputStream,ByteArrayInputStream,FileInputStream,FilterInputStream,InputStream,ObjectInputStream,PipedInputStream,SequenceInputStream,StringBufferInputStream
4.1AudioInputStream
音頻輸入資料流是具有指定音頻格式和長度的輸入資料流。長度用樣本幀表示,不用位元組表示。
4.2ByteArrayInputStream
ByteArrayInputStream
包含一個內部緩衝區,該緩衝區包含從流中讀取的位元組。內部計數器跟蹤 read
方法要提供的下一個位元組。
關閉 ByteArrayInputStream 無效。此類中的方法在關閉此流後仍可被調用
網路傳輸中我們往往要傳輸很多變數,我們可以利用ByteArrayOutputStream把所有的變數收集到一起,然後一次性把資料發送出去
int a=0; 6 int b=1; 7 int c=2; 8 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 9 bout.write(a);10 bout.write(b);11 bout.write(c);12 byte[] buff = bout.toByteArray();13 for(int i=0; i<buff.length; i++)14 System.out.println(buff[i]);15 System.out.println("***********************");16 ByteArrayInputStream bin = new ByteArrayInputStream(buff);17 while((b=bin.read())!=-1) {18 System.out.println(b);
11 byte[] buff = bout.toByteArray();
13 DataInputStream dis = new DataInputStream(bin);
4.3PipedInputStream類
管道事實上是一個隊列
樣本1:管道的輸入與輸出
import java.io.*; public class PipedIO //程式運行後將sendFile檔案的內容拷貝到receiverFile檔案中 { public static void main(String args[]) { try { //構造讀寫的管道流對象 PipedInputStream pis=new PipedInputStream(); PipedOutputStream pos=new PipedOutputStream(); //實現關聯 pos.connect(pis); //構造兩個線程,並且啟動。 new Sender(pos,"c:\\text2.txt").start(); new Receiver(pis,"c:\\text3.txt").start(); } catch(IOException e) { System.out.println("Pipe Error"+ e); } } } //線程發送 class Sender extends Thread { PipedOutputStream pos; File file; //構造方法 Sender(PipedOutputStream pos, String fileName) { this.pos=pos; file=new File(fileName); } //線程運行方法 public void run() { try { //讀檔案內容 FileInputStream fs=new FileInputStream(file); int data; while((data=fs.read())!=-1) { //寫入管道始端 pos.write(data); } pos.close(); } catch(IOException e) { System.out.println("Sender Error" +e); } } } //線程讀 class Receiver extends Thread { PipedInputStream pis; File file; //構造方法 Receiver(PipedInputStream pis, String fileName) { this.pis=pis; file=new File(fileName); } //線程運行 public void run() { try { //寫檔案流對象 FileOutputStream fs=new FileOutputStream(file); int data; //從管道末端讀 while((data=pis.read())!=-1) { //寫入本地檔案 fs.write(data); } pis.close(); } catch(IOException e) { System.out.println("Receiver Error" +e); } } }
4.4FileInputStream
用於讀取諸像資料之類的原始位元組流。要讀取字元流,請考慮使用 FileReader
。
//建立兩個檔案,face.gif是已經存在檔案,newFace.gif是新建立的檔案 File inFile = new File("face.gif"); File outFile = new File("newFace.gif"); //建立流檔案讀入與寫出類 FileInputStream inStream = new FileInputStream(inFile); FileOutputStream outStream = new FileOutputStream(outFile); //通過available方法取得流的最大字元數 byte[] inOutb = new byte[inStream.available()]; inStream.read(inOutb); //讀入流,儲存在byte數組 outStream.write(inOutb); //寫出流,儲存在檔案newFace.gif中 inStream.close(); outStream.close();
4.5FilterInputStream
不知道有什麼必要?
4.6InputStream4.7ObjectInputStream
對象序列化和還原序列化
Student stu1 = new Student(19, "zhangsan", 25, "huaxue"); Student stu1 = new Student(20, "lisi", 23, "wuli"); FileOutputStream fos = new FileOutputStream("student.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(stu1); oos.writeObject(stu2); oos.close(); FileInputStream fin = new FileInputStream("student.txt"); ObjectInputStream ois = new ObjectInputStream(fin); stu1 = (Student)ois.readObject(); stu2 = (Student)ois.readObject(); ois.close();
4.8SequenceInputStream(順序輸入資料流)
該類滿足讀取完第一個InputStream後轉去讀取第二個流的讀取要求。
該類滿足讀取完第一個InputStream後轉去讀取第二個流的讀取要求。使用Enumeration的情況下,它將繼續讀取所有InputStream流直到最後一個被讀完。text.txt與file2.txt一定要在目前的目錄下。*///Demonstrate squenced input.import java.io.*;import java.util.*;class InputStreamEnumerator implements Enumeration{ private Enumeration files; public InputStreamEnumerator(Vector files){ this.files = files.elements(); } public boolean hasMoreElements(){ return files.hasMoreElements(); } public Object nextElement(){ try{ return new FileInputStream(files.nextElement().toString()); }catch(Exception e){ return null; } }}class SequenceInputStreamDemo{ public static void main(String[] args) throws Exception{ int c; Vector files = new Vector(); files.addElement("text.txt"); files.addElement("file2.txt"); InputStreamEnumerator e = new InputStreamEnumerator(files); InputStream input = new SequenceInputStream(e); while((c=input.read())!=-1){ System.out.print((char)c); } input.close(); }}
4.9StringBufferInputStream
I/O類庫提供StringBufferInputStream類的本意是把字串轉換為位元組流,然後進行讀操作,但是在這個類的實現中僅僅使用了字元編碼的低8位,不能把字串中的所有字元(比如中文字元)正確轉換為位元組,因此這個類已經被廢棄,取而代之的是StringReader類
5、OutputStream
6個子類ByteArrayOutputStream, FileOutputStream, FilterOutputStream, ObjectOutputStream, OutputStream, PipedOutputStream
5.1ByteArrayOutputStream
其中的資料被寫入一個 byte 數組。緩衝區會隨著資料的不斷寫入而自動成長。可使用 toByteArray()
和 toString()
擷取資料。
樣本見4.2
5.2FileOutputStream
檔案輸出資料流是用於將資料寫入 File
或 FileDescriptor
的輸出資料流。
FileOutputStream 用於寫入諸像資料之類的原始位元組的流。
樣本見4.4
5.3ObjectOutputStream
將 Java 對象的基礎資料型別 (Elementary Data Type)和圖形寫入 OutputStream。
樣本見4.7
5.4FilterOutputStream
暫不研究
5.5OutputStream
暫不研究
5.6 PipedOutputStream
可以將管道輸出資料流串連到管道輸入資料流來建立通訊管道。
樣本見4.3
比較完整的類圖參見
http://blog.csdn.net/fenglian521/article/details/1324010
比較詳細的應用參見
http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html