1. 流的分類
- 按資料流的方向不同:輸入流,輸出流。
-
按處理資料機關不同:位元組流,字元流。
(1) 位元組流:資料流中最小的資料單元是位元組。
(2)字元流:資料流中最小的資料單元是字元, Java中的字元是Unicode編碼,一個字元占用兩個位元組。
-
按功能不同:節點流,處理流。
(1)程式用于直接操作目标裝置所對應的類叫節點流。
(2)程式通過一個間接流類去調用節點流類,以達到更加靈活友善地讀寫各種類型的資料,這個間接流類就是處理流。
2. 節點流
2.1 節點流的類型
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiQ3chVEa0V3bT9CX5RXa2Fmcn9CXwczLcVmds92czlGZvwVP9EUTDZ0aRJkSwk0LcxGbpZ2LcBDM08CXlpXazRnbvZ2LcRlMMVDT2EWNvwFdu9mZvwVNnpnTyUFROpXSU1EcwNjW1xWbhZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DOwkDM0ETNxETNxUDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
- (1)File 檔案流。對檔案進行讀、寫操作 :FileReader、FileWriter、FileInputStream、FileOutputStream。、
-
(2)Memory
1)從/向記憶體數組讀寫資料: CharArrayReader與 CharArrayWriter、ByteArrayInputStream與ByteArrayOutputStream。
2)從/向記憶體字元串讀寫資料 StringReader、StringWriter、StringBufferInputStream。
- (3)Pipe管道流。 實作管道的輸入和輸出(程序間通信): PipedReader與PipedWriter、PipedInputStream與PipedOutputStream。
2.2 節點流執行的圖示
3. 處理流
3.1 處理流的類型
- (1)Buffering緩沖流:在讀入或寫出時,對資料進行緩存,以減少I/O的次數:BufferedReader與BufferedWriter、BufferedInputStream與BufferedOutputStream。
- (2)Filtering 濾流:在資料進行讀或寫時進行過濾:FilterReader與FilterWriter、FilterInputStream與FilterOutputStream。
- (3)Converting between Bytes and Characters 轉換流:按照一定的編碼/解碼标準将位元組流轉換為字元流,或進行反向轉換(Stream到Reader):InputStreamReader、OutputStreamWriter。
- (4)Object Serialization 對象流 :ObjectInputStream、ObjectOutputStream。
- (5)DataConversion資料流: 按基本資料類型讀、寫(處理的資料是Java的基本類型(如布爾型,位元組,整數和浮點數)):DataInputStream、DataOutputStream 。
- (6)Counting計數流: 在讀入資料時對行記數 :LineNumberReader、LineNumberInputStream。
- (7)Peeking Ahead預讀流: 通過緩存機制,進行預讀 :PushbackReader、PushbackInputStream。
- (8)Printing列印流: 包含友善的列印方法 :PrintWriter、PrintStream。
3.2 處理流執行的圖示
3.3 緩沖流
-
【1】對I/O進行緩沖是一種常見的性能優化,緩沖流為I/O流增加了記憶體緩沖區,增加緩沖區的兩個目的:
(1)允許Java的I/O一次不隻操作一個字元,這樣提高䇖整個系統的性能;
(2)由于有緩沖區,使得在流上執行skip、mark和reset方法都成為可能。
-
【2】緩沖流:它是要“套接”在相應的節點流之上,對讀寫的資料提供了緩沖的功能,
提高了讀寫的效率,同時增加了一些新的方法。例如:BufferedReader中的readLine方法,
BufferedWriter中的newLine方法。
- 【3】J2SDK提供了4種緩存流,常用的構造方法為:
//字元輸入流
BufferedReader(Reader in)//建立一個32位元組的緩沖區
BufferedReader(Reader in, int size)//size為自定義緩存區的大小
//字元輸出流
BufferedWriter(Writer out)
BufferedWriter(Writer out, int size)
//位元組輸入流
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)
//位元組輸出流
BufferedOutputStream(OutputStream in)
BufferedOutputStream(OutputStream in, int size)
-
【4】其他
(1)緩沖輸入流BufferedInputSTream除了支援read和skip方法意外,還支援其父類的mark和reset方法;
(2)BufferedReader提供了一種新的ReadLine方法用于讀取一行字元串(以\r或\n分隔);
(3)BufferedWriter提供了一種新的newLine方法用于寫入一個行分隔符;
(4)對于輸出的緩沖流,BufferedWriter和BufferedOutputStream,寫出的資料會先在記憶體中緩存,
使用flush方法将會使記憶體的資料立刻寫出。
- 示例1:
import java.io.*;
public class TestBufferStream1 {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream(
"d:\\JavaProject\\demo13\\ProcessingStream\\TestBufferStream1.java");
BufferedInputStream bis = new BufferedInputStream(fis);
int c = ;
System.out.println((char)bis.read());
System.out.println((char)bis.read());
bis.mark();/*在目前輸入流的目前位置上做一個标志,允許最多再讀入100個位元組*/
for(int i=;i<= && (c=bis.read())!=-;i++){
System.out.print((char)c+" ");
}
System.out.println();
bis.reset();/*把輸入指針傳回到以前所做的标志處*/
for(int i=;i<= && (c=bis.read())!=-;i++){
System.out.print((char)c+" ");
}
bis.close();
} catch (IOException e) {e.printStackTrace();}
}
}
- 示例2:
import java.io.*;
public class TestBufferStream2
{
public static void main(String[] args)
{
try{
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\JavaProject\\demo13\\BufferStream\\dat2.txt"));
BufferedReader br = new BufferedReader(new FileReader("D:\\JavaProject\\demo13\\BufferStream\\dat2.txt"));
String s = null;
for(int i=;i<;i++)
{
s = String.valueOf(Math.random());//産生一個小于1的正的随機數,并轉換成字元串形式
bw.write(s);//把字元串s寫入到dat2.txt檔案中
bw.newLine();//寫入一個行分隔符
}
bw.flush();//使用flush方法将會使記憶體的資料立刻寫出
while((s=br.readLine()) != null)
{
System.out.println(s);
}
bw.close();
br.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
3.4 轉換流
-
轉換流有兩種:
(1)InputStreamReader:将位元組流轉換為字元流;
(2)OutputStreamWriter:将字元流轉換為位元組流。
- 什麼時候使用轉換流?由以下分析: 流對象很多,就要明确使用哪個流對象。
通過三點來完成:
、明确資料的來源和資料到達的目的地。
來源:輸入流 [InputStream,Reader]。
目的:輸出流 [OutputStream,Writer]。
、操作的資料是否是純文字。
是:字元流,使用Reader與Writer;
否:位元組流,使用InputStream與OutputStream。
、明确要使用哪個具體的對象。 通過裝置來進行區分:
源裝置:記憶體用數組,硬碟就加file,鍵盤用System.in;
目的裝置:記憶體用數組,硬碟就加file,鍵盤用System.out。
、明确是否還需要其他額外功能:例如
()是否需要較高的效率,即是否需要使用緩沖區,是就加上Buffered;
()是否需要轉換,是,就使用轉換流,InputStreamReader 和 OutputStreamWriter。
- 用一個例子簡單的說明: 将鍵盤錄入的資料儲存到一個檔案中,輸入“over”時表示錄入結束。 詳細分析:
源:從InputStream,Reader中選擇; 因為是鍵盤錄入的是純文字,是以使用Reader。
裝置:鍵盤,是以用System.in; 發現System.in是位元組流的操作,與Reader(字元流)沖突,
這時就要用到轉換流 InputStreamReader 。為了提高操作效率,使用緩沖技術,選擇BufferedReader。
目的:從 OutputStream,Writer中選擇。 因為是文本檔案,是以選擇Writer。
裝置:硬碟上,一個檔案,選擇FileWriter。 為了提高操作效率,使用緩沖技術,選擇BufferedWriter。
- 示例1:
import java.io.*;
class ReadinFile
{
public static void main(String[] args)throws IOException //這裡為了友善閱讀,先不做異常處理。
{
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw=new BufferedWriter(new FileWriter("readin.txt"));
String line=null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line)) break;
bufw.write(line);
bufw.newLine();
}
bufw.close();
bufr.close();
}
}
- 示例2:
import java.io.*;
public class TestTransForm
{
public static void main(String[] args) throws IOException //這裡為了友善閱讀,先不做異常處理。
{
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("D:\\JavaProject\\demo13\\TransStream\\TransForm.txt",true));
BufferedWriter bw = new BufferedWriter(osw);
String str = null;
str = br.readLine();
while(str != null)
{
if(str.equalsIgnoreCase("exit")) break;
bw.write(str);
bw.newLine();
str = br.readLine();
}
br.close();
bw.close();
}
}
-
注意:
(1)構造方法:public FileOutputStream(String name,boolean append) throws FileNotFoundException
如果append為True,輸出位元組流就寫入檔案的末尾,而不是開頭(覆寫原來的内容);
如果append為False,輸出位元組流就寫入檔案的開頭,即覆寫原來的内容從檔案開始處寫内容。
(2)構造方法:public FileOutputStream(String name) throws FileNotFoundException
每次覆寫原檔案的内容,從檔案開始處寫内容。
3.5 資料流——資料的存儲和資料恢複
-
資料流:DataInputStream和DataOutputStream
(0)DataInputStream和DataOutputStream是面向位元組的,是以要使用InputStream和OutputStream。
(1)DataInputStream和DataOutputStream分别繼承InputStream和OutputStream,
它們屬于處理流,需要分别“套接”在InputStream和OutputStream類型的節點流上。
(2)DataInputStream和DataOutputStream提供了可以存取與機器無關的Java原始類資料(如:int,double等)的方法。
(3)DataInputStream和DataOutputStream的構造方法:
DataInputStream(InputStream in)
DataOutputStream(OutputStream out)
- 示例1:
import java.io.*;
public class TestDataStream
{
public static void main(String[] args) throws IOException
{
FileOutputStream fout = new FileOutputStream("D:/JavaProject/demo13_IO/DataStream/demo.txt",true);
BufferedOutputStream bout = new BufferedOutputStream(fout);
DataOutputStream dout = new DataOutputStream(bout);
/*DataOutputStream,BufferedOutputStream,FileOutputStream這裡使用了流棧。*/
dout.writeInt();
dout.writeUTF("hello,中國");
dout.writeFloat(f);
dout.writeChar();/*97對應的是'a'*/
dout.close();/*如果正在使用一個流棧,程式關閉最上面的一個流也就自動的關閉了棧中的所有底層流。*/
FileInputStream fin = new FileInputStream("D:/JavaProject/demo13_IO/DataStream/demo.txt");
BufferedInputStream bin = new BufferedInputStream(fin);
DataInputStream din = new DataInputStream(bin);
int i = din.readInt();
String str = din.readUTF();
float f = din.readFloat();
char c = din.readChar();
fin.close();/*如果正在使用一個流棧,程式關閉最上面的一個流也就自動的關閉了棧中的所有底層流。*/
System.out.println("int:"+i+"\nString:"+str+"\nfloat:"+f+"\nchar:"+c);
}
}
- 編譯,運作:
D:\JavaProject\demo13_IO\DataStream>javac TestDataStream.java
D:\JavaProject\demo13_IO\DataStream>java TestDataStream
int:
String:hello,中國
float:
char:a
- 注意:
int i = din.readInt();
String str = din.readUTF();
float f = din.readFloat();
char c = din.readChar();
/*此段代碼的順序不能亂,要保證先寫入的先讀出來的原則,否則會出現錯誤。
* 是以,我們在寫代碼的時候,我們必須:
* 要麼為檔案中的資料采用固定的格式;
* 要麼将額外的資訊儲存到檔案中,以便能夠對其進行解析以确定資料的尋訪位置。
*/