java IO流的使用方式

 先看下圖:



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



java.io包是一組流類,分爲:
字節流:抽象父類是InputStreamOutputStream
字符流:抽象父類是Reader和Writer
[注]:I/O中的(input/output)stream無非就是包括基於字符的stream、基於字節的stream和把基於字節的stream轉換成基於字符的stream的stream。

1、 InputStream
InputStream類的體系結構


1.1、PipedInputStream:實現了pipe的概念,主要在線程中使用。管道輸入流是指一個通訊管道的兩個接收端。一個線程通過管道輸出流發送數據,而另一個線程通過管道輸入流讀取數據,這樣可實現兩個線程間的通訊。
其構造函數有:
-PipedInputStream() 創建一個管道輸入流,它還未與一個管道輸出流連接。 
-PipedInputStream(PipedOutputStream) 創建一個管道輸入流, 它已連接到一個管道輸出流。

1.2、FileInputStream 類:從實際磁盤文件讀取數據,把一個文件作爲InputStream,實現對文件的讀取操作。
其構造函數有:
-FileInputStream(File) 創建一個輸入文件流,從指定的 File 對象讀取數據。
-FileInputStream(FileDescriptor) 創建一個輸入文件流,從指定的文件描述器讀取數據。
-FileInputStream(String) 創建一個輸入文件流,從指定名稱的文件讀取數據。
它所用的方法有
- read() 從當前輸入流中讀取一字節數據。 
-read(byte[]) 將當前輸入流中 b.length 個字節數據讀到一個字節數組中。 
-read(byte[], int, int) 將輸入流中 len 個字節數據讀入一個字節數組中。

1.3、ByteArrayInputStream 類:在字節數組中執行讀寫操作,也就是把內存中的一個緩衝區作爲InputStream使用。
它的構造函數有:
-ByteArrayInputStream(byte[])創建一個新字節數組輸入流,它從指定字節數組中讀取數據。
-ByteArrayInputStream(byte[], int, int) 創建一個新字節數組輸入流,它從指定字節數組中讀取數據。
mark::該字節數組未被複制。

1.4、SequenceInputStream:把多個InputStream合併爲一個InputStream。“序列輸入流”類允許應用程序把幾個輸入流連續地合併起來,並且使它們像單個輸入流一樣出現。每個輸入流依次被讀取,直到到達該流的末尾。然後“序列輸入流”類關閉這個流並自動地切換到下一個輸入流。
構造函數有:
-SequenceInputStream(Enumeration) 創建一個新的序列輸入流,並用指定的輸入流的枚舉值初始化它。 
-SequenceInputStream(InputStream, InputStream) 創建一個新的序列輸入流,初始化爲首先 讀輸入流 s1, 然後讀輸入流 s2。


1.5、StringBufferInputStream 類:類似於ByteArrayInputStream,將字符串用作內部緩衝器,或者說是把一個String對象作爲InputStream。
[註釋]不推薦使用 StringBufferInputStream 方法。 此類不能將字符正確的轉換爲字節。
同 JDK 1.1 版中的類似,從一個串創建一個流的最佳方法是採用 StringReader 類。
其構造函數有:
-StringBufferInputStream(String) 據指定串創建一個讀取數據的輸入流串。

2、OutputStream
定義用於寫入字節或字節數組的方法。
OutputStream類的體系結構

2.1、FileOutputStream類:將數據以字節流寫入文件。(如果文件不存在則創建文件後寫入)。這裏的文件是指向File或FileDescriptor。
其構造函數有:
-FileOutputStream(File) 創建一個文件輸出流,向指定的 File 對象輸出數據。
-FileOutputStream(FileDescriptor) 創建一個文件輸出流,向指定的文件描述器輸出數據。
-FileOutputStream(String) 創建一個文件輸出流,向指定名稱的文件輸出數據。
-FileOutputStream(String, boolean) 用指定系統的文件名,創建一個輸出文件。

2.2、PipedOutputStream:管道輸出流是指一個通訊管道的發送端。一個線程通過管道輸出流發送數據,而另一個線程通過管道輸入流讀取數據,這樣可實現兩個線程間的通訊。
其構造函數有:
-PipedOutputStream() 創建一個管道輸出流,它還未與一個管道輸入流連接。
-PipedOutputStream(PipedInputStream) 創建一個管道輸出流,它已連接到一個管道輸入流。

2.3、ByteArrayOutputStream類:在內存中創建緩衝區,並把信息存入內存中的一個緩衝區中。該類實現一個以字節數組形式寫入數據的輸出流。當數據寫入緩衝區時,它自動擴大。toByteArray( )和toString( )方法用於數據檢索。
其構造函數有:
-ByteArrayOutputStream() 創建一個新的字節數組輸出流。
-ByteArrayOutputStream(int) 創建一個新的字節數組輸出流,並帶有指定大小字節的緩衝區容量。
常用方法有:
-toString(String) 根據指定字符編碼將緩衝區內容轉換爲字符串,並將字節轉換爲字符。
-write(byte[], int, int) 將指定字節數組中從偏移量 off 開始的 len 個字節寫入該字節數組輸出流。
-write(int) 將指定字節寫入該字節數組輸出流。 
-writeTo(OutputStream) 用 out.write(buf, 0, count) 調用輸出流的寫方法將該字節數組輸出流的全部內容寫入指定的輸出流參數。

2.4、FilterOutputStream類:高層輸出流

File 類:提供定位本地文件系統、描述文件和目錄的功能,是 java.io 包中引用實際磁盤文件的唯一對象。

流類可以分爲:
底層流:包含以字節的形式讀寫的方法
高層過濾器流:用於讀寫高層信息;
高層流要求底層流作爲基礎。

FilterInputStream 類的子類包括:
*DataInputStream類:提供讀取任意對象的能力
*DataOutputStream類:提供寫入任意對象的能力
*BufferedInputStream類:允許程序一次一個字節地從流讀取數據
*BufferedOutputStream類:允許程序一次一個字節地向流寫入數據
*PrintStream類:用於寫入文本或基本類型

3、Reader
讀取字符類型。
Reader類的體系結構


BufferedReader:是Reader類的子類,接受Reader 對象爲參數,爲Reader對象添加字符緩衝器,爲數據輸入分配內存存儲空間,存取數據更爲有效。
CharArrayReader:允許將字符數組用作輸入
其構造函數有:
-CharArrayReader:與ByteArrayInputStream對應 
-CharArrayReader(char[]) 用指定字符數組創建一個 CharArrayReader。
-CharArrayReader(char[],int,int) 用指定字符數組創建一個CharArrayReader。
InputStreamReader:從輸入流讀取字節,並將它們轉換成字符
FileReader:使讀取字符文件成爲可能,與FileInputStream對應。
FilterReader:允許讀取過濾字符流。
PipedReader:與PipedInputStream對應
StringReader:讀取字符串的字符,與StringBufferInputStream對應。


4、Writer
寫入字符類型。
Writer類的體系結構

BufferedWriter:將數據緩衝到字符輸出流
CharArrayWriter:允許將字符緩衝器用作輸出流,與ByteArrayOutputStream對應
FileWriter:允許將字符類型數據寫入文件,與FileOutputStream對應。
PrintWriter:包含一些使生成格式化輸出變得很簡單的方法。
StringWrite:無與之對應的以字節爲導向的stream。
FilterWriter:用於寫入過濾字符流
PipedWrite:與PipedOutputStream對應


兩種不同導向的stream之間的轉換
InputStreamReader和OutputStreamReader:把一個基於字節的stream轉換成一個基於字符的stream。InputStreamReader 類是從字節流到字符流的橋樑:它讀入字節,並根據指定的編碼方式,將之轉換爲字符流。使用的編碼方式可能由名稱指定,或平臺可接受的缺省編碼方式。
InputStreamReader(InputStream) 用缺省的字符編碼方式,創建一個InputStreamReader。
InputStreamReader(InputStream, String) 用已命名的字符編碼方式,創建一個 InputStreamReader。
InputStreamReader 的 read()有多個重載方法,用於從基本字節輸入流中讀取一個或多個字節。
爲了達到更高效率,考慮用 BufferedReader 封裝 InputStreamReader,
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

OutputStreamWriter 將多個字符寫入到一個輸出流,根據指定的字符編碼將多個字符轉換爲字節。 
   每個 OutputStreamWriter 合併它自己的 CharToByteConverter, 因而是從字符流到字節流的橋樑。

Java I/O的一般使用原則:
一、按數據來源(去向)分類:
1、是文件: FileInputStream, FileOutputStream, FileReader, FileWriter
2、是byte[]:ByteArrayInputStream, ByteArrayOutputStream
3、是Char[]: CharArrayReader, CharArrayWriter
4、是String: StringBufferInputStream, StringReader, StringWriter
5、網絡數據流:InputStream, OutputStream, Reader, Writer
二、按是否格式化輸出分:
1、要格式化輸出:PrintStream, PrintWriter
三、按是否要緩衝分:
1、要緩衝:BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter
四、按數據格式分:
1、二進制格式(只要不能確定是純文本的): InputStream, OutputStream及其所有子類
2、純文本格式(含純英文與漢字或其他編碼方式):Reader, Writer及其所有帶Reader, Writer的子類
五、按輸入輸出分:
1、輸入:Reader, InputStream類型的子類
2、輸出:Writer, OutputStream類型的子類
六、特殊需要:
1、從Stream到Reader,Writer的轉換類:InputStreamReader, OutputStreamWriter
2、對象輸入輸出:ObjectInputStream, ObjectOutputStream
3、進程間通信:PipeInputStream, PipeOutputStream, PipeReader, PipeWriter
4、合併輸入:SequenceInputStream
5、更特殊的需要:PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader

使用原則:
決定使用哪個類以及它的構造進程的一般準則如下(不考慮特殊需要):
首先,考慮最原始的數據格式是什麼: 原則四
第二,是輸入還是輸出:原則五
第三,是否需要轉換流:原則六第1點
第四,數據來源(去向)是什麼:原則一
第五,是否要緩衝:原則三 (特別註明:一定要注意的是readLine()是否有定義,有什麼比read, write更特殊的輸入或輸出方法)
第六,是否要格式化輸出:原則二

例子程序:

package StreamLearn;

import java.io.*;

public class TestFileInputStream {
	public static void main(String[] args) {
		int count=0;
		Reader r=null;
	    //1.確定原始數據是文本文件,因此用閱讀器Reader(父類調用子類方法,不管是什麼樣的Reader都可以
		//2.確定爲輸入,因此爲InputStreamReader
		//3.確定數據來源爲文件因此用FileInputStream
		//4.爲了提高程序效率,使用緩衝流 bufferedInputStream
		try{
			r =new InputStreamReader(
				new BufferedInputStream(new FileInputStream("c:\\a.txt"),1024));
		}catch(FileNotFoundException e)
		{
			System.out.println("can not find it");
			System.exit(1);
		}
	    
	
		long num=0;
		try{
		
			while((count=r.read())!=-1){
				System.out.print((char)count);
				//System.out.println(count);
				num++;
			}	
		   }catch(IOException e)
		   {
			   e.printStackTrace();
		   }
		   System.out.println("\n字符個數:"+num);
	  }
    
	  
}


txt文件 規則

頭2個字節如果是 fe ff 表示編碼格式爲unicode big endian;
頭2個字節如果是 ff fe 表示 unicode;
頭3個字節如果是 ef bb bf 表示 utf-8

package Random;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
public class Write {
	public static String bytesToHexString(byte[] src){  
	    StringBuilder stringBuilder = new StringBuilder("");  
	    if (src == null || src.length <= 0) {  
	        return null;  
	    }  
	    for (int i = 0; i < src.length; i++) {  
	        int v = src[i] & 0xFF;  
	        String hv = Integer.toHexString(v);  
	        if (hv.length() < 2) {  
	            stringBuilder.append(0);  
	        }  
	        stringBuilder.append(hv);  
	    }  
	    return stringBuilder.toString();  
	}  
public static void main(String []arsg)throws Exception
{
	String sep=File.separator;
	File dir=new File("C:"+sep+"myTest.txt");
   FileInputStream fis=new FileInputStream(dir);
   byte[]b=new byte[3];  
   fis.read(b,0,3);
   System.out.println(bytesToHexString((b)));
}}

上面程序在讀取“utf-8”編碼的txt文檔前三個字節時候 輸出結果爲ef bb bf。在讀文件時,應該按照文件的編碼格式來讀取,如果不對應,會產生亂碼。

如 BufferedReader BR=new BufferedReader(new InputStreamReader(new FileInputStream(dir),"UNICODE"));用來讀取unicode編碼的文件

             BufferedReader BR=new BufferedReader(new InputStreamReader(new FileInputStream(dir),"utf-8"));用來讀取uft-8編碼的文件

            可用程序按照規則來判斷。也可以採用文件另存爲方式指定文件編碼方式,按照編碼方式來讀取。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章