黑馬程序員——Java I/O系統

數據處理在程序內部執行,待處理的數據需要傳入程序,處理後的數據可能會需要傳出程序,數據在程序內部和外部之間的這種傳輸動作叫做IO操作。
與程序進行IO的端有控制檯、文件(硬盤)、網絡端口甚至是內存,對應包裝的IO流對象有System.in、System.out,用文件名創建的輸入輸出流對象,由Socket獲得的輸入輸出流對象、字節數組或者字符串等。

Java中字節流的基本框架如圖一:

圖一

字符流的基本框架如圖二:


圖二

如圖中描述的,字節流的基本來源有由System.in或System.out獲得鍵盤或控制檯的流,由String或File對象獲得文件的流(輸入 或輸出),由Socket(getInputStream()方法或getOutputStream()方法)獲得網絡流(輸入或輸出),由字節數組或字符串獲得內存內部數據的流;字符流有由String或File對象直接獲得的文件的流(輸入或輸出),有由字符數組或字符串獲得內存內部數據的流。剩下的流基本都是對這些基本流的包裝(構造時將這些基本流的對象傳入,並將基本流對象作爲該類的成員,建立各種針對該基本流對象成員的方法)。

一、字節流

字節輸入流就是用來讀取的,其讀取方法有:

int read()讀取一個字節,並將該字節放於返回的int值的最低字節中,若讀到流末尾返回-1

int read(byte[] b)將流中的字節讀入b字節數組,在流中數據足夠的情況下讀慢b數組,若讀至流末尾返回-1

int read(byte[] b,int offset,int len)從流中讀取最多len個字節,讀入b字節數組中偏移爲offset處。返回讀取的字節數,若讀到流末尾返回-1

字節輸出流就是用來寫入的,其寫入方法有:

void write(int b)   將int值b的最低一個字節寫入流

void write(byte[] b)將b中的數組全部寫入流中

void write(byte[] b,int offset,int len)b字節數組中從0索引偏移offset處開始的len個字節,寫入流中

包裝流基本都包含基本流的這三種方法,但在此基礎上又有其它方法。

1.Buffered流:

Buffered流都有一個緩衝區,用於在實際讀取流和寫入流之前進行數據緩衝。BufferedInputStream每次在調用讀取方法時,都預先將其內部的緩衝區讀滿(如果流中數據足夠的話),然後再從該緩衝區中讀取,無論是讀一個字節還是讀若干字節到某個字節數組中,都是從該緩衝區數組中讀取,並有指針和計數器用於標記緩衝區讀取位置和剩餘的未讀取字節數。BufferedOutputStream每次在調用寫入方法時,無論是調用寫入一個字節還是寫入一個字節數組,都將這些數據先寫入內部的緩衝區,待調用flush()方法或關閉流時再將緩衝區中的數據寫入流。緩衝流提高了讀取和寫入的效率。

2.Data流:

Data流(DataInputStream或DataOutputStream)提供了直接讀取和寫入基本數據類型的方法。該流很重要。

3.轉換流:

通過以String的形式提供編碼表,加入此編碼表或使用默認的編碼表將字節流包裝成字符流。這是非常重要的流,用於將字節流轉換成字符流。字符輸入流在讀取時能根據其編碼表按照字符讀取,字符輸出流在寫入時能按照其編碼表將字符或字符數組寫入流。

4.合併流:

該流用於將多個流合併,其本質類似於將多個流讀取到一個流,故該流只限於輸入流。

SequenceInputStream(Enumeration<? extends InputStream> e)

SequenceInputStream(InputStream in1,InputStream in2)

構造方法中用到的Enumeration<? extends InputStream>可以由Vector<InputStream>的elements()方法獲得。被合併的流中除最後一個流之外,其它流的結束標記不再被當作結束標記,只保留最後一個流的結束標記。

5.打印流:

打印流顧名思義只限於輸出流,打印流有特殊的方法集(print(...)或println(...)),能夠直接將基本數據類型打印入流,這些打印方法和Data流中的將基本數據類型寫入流的方法不同,Data流中寫入方法是將基本數據類型直接按原字節內容寫入(byte寫入1個自己,short寫入2個字節,int寫4個字節,long寫入8個字節......),而打印流的打印方法是將基本數據類型轉換成字符串再寫入這些字符串。另外打印流還有特殊的構造方法,打印流既能用字節輸出流構造又能用字符輸出流構造。

6.管道流:

管道流也可以理解成基本流對象,管道輸入流是管道輸出流的源,管道輸出流是管道輸入流的目的地,管道輸入流.面向的方法是int read()或int read(byte[] b)等方法從管道的另一端讀取數據,管道輸出流面向的方法是void write(int b)或void write(byte[] b)等方法將字節或字節數組寫入管道流並流向管道輸入流。一般將管道流的兩端放在不同的線程中。
構造管道流的方法有:
1)分別創建管道輸入流和管道輸出流,再通過connect(...)方法連接;
2)  創建管道流的一端,再在構造另一端時將此端傳入。

二、字符流

System.in是字節流,System.out是打印流,這兩個端口沒有爲字符流提供直接創建的類;此外,網絡端口也只能直接獲得字節流。但是可以通過String(提供文件路徑或文件名)或File對象直接創建文件的字符流對象,還可以直接通過字符數組或字符串創建字符流對象。

其它非基本字符流類基本都是對基本字符流類的包裝,即傳入一個Writer對象或Reader對象。打印流仍然只有輸出流,也仍然是既可以用字節流又可以用字符流創建。

字符流同字節流相比,讀和寫的數組由字節數組變爲字符數組;字符緩衝流同字節緩衝流相比,BufferedWriter增加了void newLine()方法,BufferedReader增加了
String readLine()方法。

三、RandomAccessFile
該類不是繼承自InputStream、OutputStream、Reader、Writer等的類,但它內部有IO流對象的成員,它只能用於爲文件創建流。其構造方法有兩種,都傳入兩個參數一個用於提供文件,一個用於提供開啓文件的模式。可以用String提供文件名(包括路徑)或用File對象提供文件,提供文件開啓模式是用String變量,可選模式只有四種:
“r”——只讀
“rw”——讀寫
“rws”——打開以便讀取和寫入,對於 "rw",還要求對文件的內容或元數據的每個更新都同步寫入到底層存儲設備。
“rsd”——打開以便讀取和寫入,對於 "rw",還要求對文件內容的每個更新都同步寫入到底層存儲設備。

該類十分類似C語言打開文件的方式。有打開模式,既能讀又能寫。
同時,RandomAccessFile還能調整流中指針的位置,用到的方法是void seek(long pos)(讓文件指針位置移到從文件開頭向後偏移pos個字節處)和int skipBytes(int n)(讓文件指針從當前位置向後移動n個字節)。
同時,該類對象還提供了和DataStream一樣的對基本數據類型的讀和寫的方法。

四、其它特性

輸入流中,System.in、網絡端口輸入等的讀取方法都是阻塞式方法,當未讀到信息時,該方法會等,其它輸入流的讀取方法不是阻塞式的,當讀到流末尾時,返回-1。

五、File

File類是文件或目錄路徑名的抽象表現形式,該類對象用來表示一個文件或文件夾。該類對象創建時,不一定對應的在存儲設備上存在相應的文件或文件夾,File對象建立好後也不一定對應文件還是文件夾,對應文件還是文件夾的一個因素是在於存儲設備上現有的同名File是文件還是文件夾,另一個因素是,若存儲設備上沒有該名的File,則使用createNewFile()方法後建立的是文件,使用mkdir()或mkdirs()方法後建立的就是文件夾,其中mkdir()只能創建一層目錄,mkdirs()可以創建多層目錄。

File類的構造方法:
File類構造時需要傳入參數以提供文件或目錄的絕對路徑或相對路徑。該路徑可以單獨以String形式提供也可以分成兩部分提供,第一部分可以是File對象也可以是String,第二部分只能是String;又或者可以傳入一個URL類對象以構造File。

File類的其它方法:
疑問: canExecute()對於存在的文件或目錄都返回true;
對於文件調用setExecutable(false)都返回false,即不能設置成不可執行;
對於文件調用setReadable(false)都返回false,即不能設置成不可讀。
setWritable(boolean b)和canWrite()方法都能正常執行。用於設置和判斷可寫性。
isFile()和isDirectory()用於判斷是文件還是文件夾。
exists()方法用於判斷是否存在。
另外還有一組很重要的方法:list  該組方法只用與目錄也就是文件夾
String[]  list()
String[]  list(FilenameFilter f)
File[]  listFiles()
File[]  listFiles(FilenameFilter f)
File[]  listFiles(FileFilter f)
這些方法區別在於返回字符串還是File類對象,返回全部文件還是加以過濾。
由此引出FilenameFilter接口和FileFilter接口,兩個接口都要求實現accept方法但是傳入參數不同,FilenameFilter要實現boolean accept(File dir,String name),FileFilter要實現boolean accept(File pathname),list方法要的就是該accept方法返回的布爾值。
另外還有一個靜態方法:static File[] listRoots()  用於返回當前系統的根目錄的File數組。

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