輸入輸出可以說是計算機的基本功能。作為一種語言體系,java中主要按照流(stream)的模式來實現。其中數據的流向是按照計算機的方向確定的,流入計算機的數據流叫做輸入流(inputStream),由計算機發出的數據流叫做輸出流(outputStream)。
Java語言體系中,對數據流的主要操作都封裝在java.io包中,通過java.io包中的類可以實現計算機對數據的輸入、輸出操作。在編寫輸入、輸出操作代碼時,需要用import語句將java.io包導入到應用程序所在的類中,才可以使用java.io中的類和接口。
Java數據流相關的操作類
在java.io包中提供了外部設備和計算機之間進行數據傳輸的輸入、輸出操作類。主要的操作類及其之間的繼承關系如下圖所示。從上往下依次是父類和子類的關系。
java.io包中針對輸入、輸出流目前支持針對字節(或者ASCII編碼的字符)和Unicode編碼的字符數據流傳輸。其中支持字節流傳輸的類包括InputStream和OutputStream類,支持Unicode編碼的字符流傳輸的類有Reader和Writer類,這些類都是抽象類,是所有操作數據流的類的父類,它們提供了操作數據流的標准的基礎方法,由子類具體實現數據流的輸入、輸出操作。
需要注意的是,如果傳輸的數據流的類型是其他類型,需要先將這些數據對象進行序列化(serializable),即串行化。如此可以將數據對象轉換為順序的字節流,然后就可以使用java.io中提供的各種輸入輸出操作方法進行數據傳輸。(實際數據的序列化通過實現java.io中提供的Serializable接口來完成)
控制台輸入、輸出操作分析
控制台輸入、輸出操作都是靜態的。它的原理是在java虛擬機啟動后,提供輸入、輸出操作的類對象會始終駐留在內存中。這里提供輸入、輸出操作的類對象被定義在java.lang包中的system類中,類對象的名稱是in、out和err,而java.lang包是嵌入在java虛擬機中的,並且在java虛擬機啟動以后將該包中的類創建為對象駐留在了內存中。因此說system類所提供的輸入輸出操作為靜態的。
實際上,在基本的控制台輸入輸出操作中,主要有兩個方法read()和print()。其中read()負責輸入,print負責將其輸入的內容顯示到屏幕。關於read()方法,在system類中共給出了三種參數類型:
System.in.read(); |
System.in.read(byte[] b); |
System.in.read(byte[] b, int off, int len) |
Read()方法的作用就是從終端命令行中讀取字符到java程序中,讀取的數據的范圍在0~255之間。Read()方法一次只能從終端讀取一個字符,這個字符取值范圍在byte范圍內,但是返回值類型是int型。
不帶參數的read()方法在讀取字符時,讀到用戶按下回車鍵或者數組被填滿為止。兩種帶參數的read()方法中是把讀取到的字符存入byte數組中,最后的帶有3個參數的read()方方法的解釋:后面兩個參數指明了讀到的字符放入byte數組中的起始位置和最多讀取的字符個數。
(1)System.in
作為標輸入輸出,system.in是InputStream類的對象,當程序中需要從鍵盤讀入數據時,只需要調用system.in中的read()方法即可。不過,在調用read()方式時必須捕獲System.in.read()拋出的異常。System.in.read()是從鍵盤緩沖區讀入一個字節的數據,返回16位的數據,其低位是真正輸入的數據,而高位為0;當輸入數據時,如果鍵盤緩沖區沒有數據,系統將會進入阻塞狀態,因此,常常可以利用System.in.read()的這個特點實現程序的暫停,用戶輸入后繼續往下執行。
(2)System.out
System.out是標准輸出流,打印輸出流printStream類的對象,它定義了能夠向顯示屏輸出各種數據類型的pingt()和println()方法。包括boolean,double,float,int,long類型的變量以及Object類的對象等等。當輸出類型為對象時,它將自動調用對象的toString()方法,因此在對象所在的類中需要重寫toString()方法並輸出特定的文字。
(3)標准輸入輸出的重定向
重定向也就是改變標准輸入輸出的方向,具體的實現方法可以通過調用system類中提供的3個static方法實現:setln(InputStream in)、setOut(PrintStream out)、setErr(PrintStream out)
文件輸入、輸出操作
Java在操作磁盤文件時,將磁盤文件當做對象,把文件中存儲的內容看做數據流,當通過文件來創建數據流時(將數據流對象和文件對象綁定),對數據流對象的輸入、輸出操作實際上都看做是對文件的讀寫操作。此處,文件中的數據流也看做是有順序的數據流,特別的一點是文件中數據流最后一個流結束符數據是一個文件結束符(EOF)數據。
實際上,關於文件/目錄讀寫操作相關的類、接口以及方法常用的主要有:FileInputStream/FileOutputStream、PipedInputStream/PipedOutputStream、隨機文件讀寫、字符流Reader/Writer、DataInput/DataOutput接口、DataInputStream 和DataOutputStream過濾流、標准輸入輸出流等。
(1)文件操作
在java語言體系而中,將要處理的文件類型分為兩種:文本文件和非文本文件(圖片、視屏等都屬於非文本文件)。其中文本文件的內容是以16bit(2字節)表示的,而非文本文件則是以8bit(1字節)表示的。兩種文件讀寫操作上有比較大的區別,主要體現在:對文本文件而言,其讀寫處理的單位是字符(兩個字節一組,可以解析為字符);而對非文本文件(流)而言,其讀寫是以單個字節為單位的,單獨的字節在java中不能解析為字符。因此說兩種文件的處理有較大不同。
(2)File類
與文件讀寫相關的類都包含在java.io庫中,讀入一般使用Input或者reader,而寫出一般使用out或者writer。而流式一種利用緩沖機制實現將數據從生產者(如鍵盤、磁盤文件、內存或者其他設備)傳送到接收該數據的消費者(比如屏幕、文件或者內存等)的過程的抽象表達。
文本文件讀入 |
Reader |
文本文件寫出 |
Writer |
流文件讀入 |
inputStream |
流文件寫出 |
outputStream |
而文件類File則主要用於創建文件對象的類,可以處理和文件名以及目錄名有關的操作。File類獨立於系統平台之外,利用其構造函數創建file對象,然后通過對象引用其成員函數實現對文件的各個屬性的操作,實現對文件和目錄的管理。即,通過File類所提供的方法可以得到文件或者目錄的描述信息,比如文件名稱、所在路徑、可讀性、可寫性、文件長度等等;還能生成新的目錄、改變文件名、刪除文件、列出某個指定目錄下的所有文件等。
(3)字節流文件操作的一般方法
輸入輸出操作的抽象基類有InputStream、OutputStream,實現對文件內容基本操作的常用方法有read()、write()、close()等。通常在實際的使用中,都是通過為InputStream、OutputStream創建派生類對象來實現對具體文件的讀寫。在這個過程中需要注意對異常的處理。
在java.io中定義的字節輸入輸出操作類都適合於對磁盤文件的讀寫操作。比如,直接用於磁盤文件讀寫操作的類有FileInputStream、FileOutputStream等,這些類可以通過綁定文件對象來創建輸入、輸出流對象,也可以直接指定磁盤文件名創建輸入、輸出流對象,通過對輸入、輸出流對象執行讀寫操作實現對指定文件的讀寫操作。
對文件操作的一般步驟是:
1)根據具體的操作類型,生成一個輸入輸出文件類的對象;
2)調用此類的成員函數實現對文件內容的讀寫操作;
3)關閉文件。
在對文件操作需要注意的是:
1)異常處理:因為在java.io包中,幾乎對所有的類都聲明了I/O異常,因此用戶在編寫程序時應該對這些異常加以處理;
2)流結束標識:當read()方法返回值為-1時,readline()方法返回值為NULL時。
(4)字符流文件的操作reader/writer
Reader/writer被稱作字符流處理類,提供對字符的處理。不過Reader/writer也都是抽象類,屬於它們的子類有InputStreamReader(InputStream in) / OutputStreamWriter(OutputStream out),BufferedReader(InputStreamReader isr, int size) / BufferedWrite(OutputStreamWriter osr, int size)等。
概括來說,java.io中定義的FileReader/FileWriter、BufferedReader/BufferedWrite、PrintWriter等類都是針對字符數據流的輸入輸出操作而言的。
1)InputStreamReader/OutputStreamWriter可以使用指定的編碼規范並基於字節流生成對應的字符流。比如:
FileInputStream fis=new FileInputStream("example.txt");
InputStreamReader isr=new InputStreamReader(fis," iso-8859-1");
說明:為了能夠在讀取不同的字符時不出現亂碼,可以才用 iso-8859-1編碼規范,它是一種映射到ASCII碼的編碼方式,可以實現不同平台系統之間的字符的正確轉換。
2)BufferedReader/BufferedWrite是為了提高字符流處理效率而引入的緩沖機制流處理類,實現了對字符流的批量處理。其中的readline()方法一次讀取一整行字符,newLine()則是一次寫入一整行字符。緩沖機制的引入使得可以把任意輸入流/輸出流“綁定”到緩流上獲得性能的提升。緩沖區的大小可以再創建緩沖流對象時設置。
值得注意的是,在java語言中,處理命令行方式的鍵盤輸入時,系統把輸入的內容當做字符串看待,但是java並沒有提供自動將輸入串轉換為其他類型數據的方法,因此,當需要從鍵盤接收數據時,必須由應用程序自己實現類型轉換操作。
從本文前面的數據處理相關的類圖關系可以看出,FileReader和FileWriter是文件字符流操作類。因為InputStreamReader(功能是將字節流轉換為字符流)和OutputStreamWriter(功能是將字符流轉換為字節流)字符流類在創建流類對象時必須以單個字節流作為原始數據流來打開一個文件,為了能夠直接將一個具體文件名的文件直接轉換為字符流類的對象,在java.io中提供了FileReader和FileWriter,它們分別是InputStreamReader和OutputStreamWriter的子類,適合於字符流數據的輸入輸出操作。