1、Java IO 流
io是java中實現輸入輸出的基礎,它可以很方便的完成資料的輸入輸出操作,Java把不同的輸入輸出抽象為流,通過流的方式允許Java程式使用相同的方式來訪問不同的輸入、輸出。
2、流的分類
輸入資料流、輸出資料流
A、輸入資料流:只能從中讀取資料,而不能向裡面寫資料
B、 輸出資料流:只能向裡面寫資料,而不能讀資料
可以這樣理解,資料從記憶體到硬碟,通常認為是輸出資料流,即寫操作;相反,從硬碟到記憶體,通常認為是輸入資料流,即讀操作;這裡的輸入、輸出是從記憶體的角度劃分的。
Java的輸入資料流主要有InputStream和Reader作為基類,而輸出資料流則主要由OutputStream和Writer作為基類;
位元組流和字元流
位元組流和字元流區別非常簡單,它們的用法幾乎一樣。區別在於位元組流和字元流所操作的資料單元不同:位元組流操作的最小單中繼資料是8位位元組,而字元流作為最小資料單元是16為位元組。
位元組流主要由InputStream、OutputStream作為基類,而字元流則主要由Reader和Writer作為基類完成。
節點流和處理流
按照流的角色分,可以分為節點流和處理流。
可以從、向一個特定的IO裝置,讀寫資料流,稱為節點流,節點流常常也被常務低級流(Low Level Stream)
處理流則用於對一個已經存在的流進行串連封裝,通過封裝後來實現資料的讀寫功能。處理流稱為進階流;
當用處理流的進行輸入、輸出時,程式並不會直接連接到實際資料來源,沒有和實際的輸入、輸出節點串連。使用處理流一個明顯的好處是:只要使用相同的處理流,程式就可以採用相同的輸入、輸出代碼來訪問不同資料來源,隨著處理流鎖封裝節點流的改變,程式實際所訪問的資料來源也相應發生改變。
處理流的功能主要體現在兩個方面:
效能提高:主要以增加緩衝方式來提高輸入、輸出的效率
操作的便捷: 處理流可能提供了系列便捷的方法來一次性輸入、輸出大批量的內容,而不是輸入、輸出一個或多個單位元據
處理流可以“嫁接”在任何已經存在的流的基礎上,這就允許Java應用程式採用相同的代碼、透明的方式來訪問不同的輸入、輸出裝置輸入資料流。
位元組輸入資料流InputStream和字元輸入資料流Reader
InputStream和Reader是所有輸入資料流的基類,他們都是2個抽象類別,本身並不能建立執行個體來執行輸入,但他們有輸入資料流的模版,所以它們的方法是所有的輸入資料流和輸出資料流可以用的方法。
在InputStream裡常用的方法:
int read(): 從輸入資料流中讀取單個自己
int read(byte[] b): 從輸入資料流中讀取最多b.length個位元組,將讀取的位元組存在數組b中,返回實際讀取的位元組數
int read(byte[] b, int off, int len): 從輸入資料流中讀取最多len個位元組資料,並將其儲存在數字b中,放入b數組中時,並不是從數組起點開始,而是從off位置開始,返回實際讀取位元組數。
在Reader裡經常使用的方法:
int read(): 從輸入資料流中讀取單個字元
int read(char[] c): 從輸入資料流讀取最多c.length個字元資料,並將其儲存在字元數組c中,返回實際讀取的字元
int read(char[] c, int off, int len): 從輸入資料流中讀取最多len個字元的資料,將讀取的資料放到字元數組c中儲存,從數組的off開始讀取;
InputStream、Reader還支援如下幾個方法移動指標:
void mark(int readAheadLimit): 在記錄指標當前位置第一個標記(mark)
boolean markSupported(): 判斷此輸入資料流是否支援mark()操作,即是否支援記錄標記
void reset():將此流的記錄的指標重新置放到上一次記錄的標記的位置
long skip(long n):記錄指標向前移動n個位元組、字元
OutputStream位元組輸出資料流和Writer字元輸出資料流
具有以下方法:
void write(int c): 指定的位元組、字元輸出到輸出資料流中
void write(byte[]/char[] buf): 將位元組數組/字元數組中的資料轉送到指定輸出資料流中
void write(byte[]/char[] buf, int off,int len):將指定數組中的資料輸出到指定輸出資料流中
字元輸出資料流還有以下方法:
void write(String s):將指定字串輸出到指定輸出資料流中
void write(String s, int off, int len):將位元組數組、字元數組中從off位置開始,長度為len的位元組、字元輸出到輸出資料流中
3、Java的輸入、輸出資料流:
分類 |
位元組輸入資料流 |
位元組輸出資料流 |
字元輸入資料流 |
字元輸出資料流 |
抽象基類 |
InputStream |
OutputStream |
Reader |
Writer |
訪問檔案 |
FileInputStream |
FileOutputStream |
FileReader |
FileWriter |
訪問數組 |
ByteArrayInputStream |
ByteArrayOutputStream |
CharArrayReader |
CharArrayWriter |
訪問管道 |
PipedInputStream |
PipedOutputStream |
PipedReader |
PipedWriter |
訪問字串 |
|
|
StringReader |
StringWriter |
緩衝流 |
BufferedInputStream |
BufferedOutputStream |
BufferedReader |
BufferedWriter |
轉換流 |
|
|
InputStreamReader |
OutputStreamWriter |
物件流程 |
ObjectInputStream |
ObjectOutputStream |
|
|
抽象基類 |
FilterInputStream |
FilterOutputStream |
FilterReader |
FilterWriter |
列印流 |
|
PrintStream |
|
PrintWriter |
推回輸入資料流 |
PushbackInputStream |
|
PushbackReader |
|
特殊流 |
DataInputStream |
DataOutputStream |
|
|
輸入、輸出資料流的體系:
推回輸入資料流:
有2個特殊流與眾不同,就是PushbackInputStream、PushbackReader,它們有以下常用方法:
void unread(byte[]/char[] buf):將一個位元組/字元數組推到緩衝區裡,運行重複讀取推回的內容
void unread(byte[]/char[] buf, int off, int len):將一個位元組/字元數組從off位置開始讀取,長度是len的字元/位元組數組的內容推回到緩衝區中,允許重複剛才讀取的內容
void unread(int b):將一個位元組、字元推回到緩衝區
這2個推回輸入資料流都帶一個緩衝區,當程式調用unread的時候,系統就會把指定數組的內容推回到緩衝區,而推回輸入資料流每次調用read的方法,總會先去讀取推回緩衝區中的內容,只有完全讀取的緩衝區裡面的內容後,而且還沒有裝滿read所需的數組,才會到原輸入資料流中讀取內容;
重新導向標準輸入輸出
在System中有3大標準輸入、輸出方法:
static void setErr(PrintStream e):重新導向“標準”錯誤輸出資料流
static void setIn(InputStream in):重新導向“標準”輸入資料流
static void setOut(OutputStream out):重新導向“標準”輸出資料流
JVM寫其他進程資料
Runtime對象有exec方法,他可以運行jvm命令列,該方法產生一個Process對象,Process對象代表由該Java程式啟動的子進程,Process類有以下方法,可以和子進程通訊;
InputStream getErrorStream():擷取子進程的錯誤流
InputStream getInputStream():擷取子進程的輸入資料流
OutputStream getOutputStream():擷取子進程的輸入資料流
4、RandomAccessFile
RandomAccessFile是Java輸入、輸出體系中功能最豐富的檔案內容訪問類,它提供了眾多方法來訪問檔案內容,它既可以讀檔案內容也可以像檔案輸出資料。它和普通的輸入、輸出資料流不同的是,它可以隨機訪問的方式,操作檔案資料。
RandomAccessFile可以自由定位檔案指標,所以RandomAccessFile可以不從開始的地方輸出,RandomAccessFile可以向已經存在的檔案後追加內容。
RandomAccessFile對象包含一個指標用來記錄當前讀寫的位置,當程式新建立一個RandomAccessFile對象時,該指標位於檔案頭部,既0的位置;當讀取或寫入了n個位元組後,檔案指標就指向最後的位置,除此之外,檔案指標也是可以隨意移動的,RandomAccessFile有以下方法操作指標:
long getFilePointer():返迴文件記錄指標的當前位置
void seek(long pos):將檔案記錄指標定位到pos位置
RandomAccessFile既可以讀也可以寫,所以它包含了完全類似於InputStream的read方法,和OutputStream的write方法,用法和原來的都一樣;而且RandomAccessFile還包含了readXxx、writeXxx的輸入輸出方法;
RandomAccessFile的檔案訪問模式:
r:以唯讀方式開啟指定檔案
rw:以讀取、寫入方式開啟指定檔案,如果檔案不存在就建立
rws:以讀取、寫入的方式開啟指定檔案,相對應rw模式,還要求檔案內容和中繼資料的每個更新都同步寫入到底層存放裝置
rwd:以讀取、寫入方式開啟指定檔案,對於rw,還要求檔案內容的每個更新都同步寫入到底層裝置
5、序列化
在遠程調用、分布式開發中常用到序列化,將java對象序列化的檔案中儲存,然後在解析的時候又還原序列化,其中需要用到Serializable介面;在實現了該介面的對象可以順利序列化成一個檔案儲存在硬碟上,還原序列化也是通過該介面的id來尋找該對象的。
transient可以忽略對象中某個屬性不被序列化。
6新NIO
nio常用的包介紹:
java.io 包:主要提供了一些和Buffer相關的類
java.io.channels:包括Selector和Channel的相關類
java.nio.charset:包含和字元集相關的類
java.nio.channels.spi:提供Channel服務類
java.nio.charset.spi:提供文字集的服務類
Buffer介紹
Buffer是提取資料的容器,這裡有ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。
上面這些類,除了ByteBuffer之外,都採用類似的方法管理資料,只是各自管理的資料類型不同而已。這些Buffer都沒有構造器,通過使用如下方法來得到一個Buffer對象:
static XxxBuffer allocate(int capacity) 建立一個容量為capacity的XxxBuffer對象
ByteBuffer的子類MappedByteBuffer,它用於表示Chanael將硬碟檔案的的部分或全部內容映射到記憶體中後得到結果,通常MappedByteBuffer對象由Chanael的map方法返回。
在Buffer中有三個重要的概念:容量(capacity)、界限(limit)、位置(position)
容量(capacity):緩衝區的容量(capacity)表示該Buffer的最大資料容量,即最多可以儲存多少資料,緩衝區的容量不能為負數,在建立後是不能改變的。
界限(limit):第一個不應該被讀出或寫入的緩衝區位置索引。也就是說,位於limit後的資料既不能讀,也不能寫。
位置(position):用於指明下一個可以讀出的後者寫入的緩衝區位置索引。類似於IO流中的記錄指標位置。當剛剛建立一個Buffer對象時,容器position為0,如果從Channel讀取了2個資料到該Buffer中,則postion為2,指向Buffer中的第三個。
Buffer常用方法:
int capacity():返回Buffer的capacity的大小
boolean hasRemaining():判斷當前位置(position)和界限(limit)之間是否還有元素可以提供處理。
int limit:返回Buffer的界限(limit)的位置
Buffer limit(int newLimit)重新設定界限的值,並返回一個具有新的limit的緩衝區的對象
Buffer mark():設定Buffer的mark位置,它只能在0和位置position之間做mark
int position():返回當前Buffer的position
Buffer postion(int newPostion):設定Buffer的新位置,並返回一個具有新的limit的緩衝區對象。
int remaining():返回當前位置和界限之間的元素個數
Buffer reset():將position位置設定到mark的位置
Buffer rewind():將位置(position)設定為0,取消設定的mark
當使用put和get來訪問Buffer中的資料時,分為絕對和相對的2種:
相對的Relative:從Buffer中的當前位置讀取和寫入資料,然後將位置(position)的值按處理元素的個數相加。
絕對Absolute:直接根據索引來向Buffer中讀取或寫入資料,使用絕對方式來訪問Buffer理的資料,並不會影響位置position的值。