[Java] I/O底層原理之一:字符流、字節流及其源碼分析


關於 I/O 的類可以分為四種:

  1. 關於字節的操作:InputStream 和 OutPutStream;
  2. 關於字符的操作:Writer 和 Reader;
  3. 關於磁盤的操作:File;
  4. 關於網絡的操作:Socket( Socket 類不在 java.io 包中)。

在本篇博客中主要講述前兩種 I/O,即字符流與字節流,並會提及磁盤IO。首先我們來看一下字節流與字符流的實現關系,如下圖

 

一、字節流

在字節流的類中,最頂層的是 Inputstream 抽象類和 OutputStream 抽象類,兩者定義了一些關於字節數據讀寫的基本操作。他們的實現類有

  • ByteArrayInputStream/ByteArrayOutputStream // 都對“字節數組”進行操作(寫入/讀出),兩者可單獨使用
  • FileInputStream/FileOutputStream // 都對“文件”進行操作(寫入/讀出),兩者可單獨使用
  • ObjectInputStream/ObjectOutputStream // 用於“對象”與“流”之間的轉換,兩者可單獨使用
  • PipedInputStream/PipedOutputStream // 建立一個鏈接(像管道),用於雙方傳輸流數據,兩者要一起使用
  • FilterInputStream/FilterOutputStream // 裝飾類,可以為其他類增加功能,應用了裝飾者模式
    • BufferedInputStream/BufferedOutputStream // 可以為被裝飾的類增加緩沖功能
    • DataInputStream/DataOutputStream // 可以為被裝飾的類增加寫讀指定數據類型的功能
    • LineNumberInputStream // 可以為被裝飾的類增加獲取行數的功能,現已被 LineNumberReader 替代
    • PushbackInputStream // 可以將當前讀取的數據推回到緩沖區
    • PrintStream
  • SequenceInputStream
  • StringbufferInputStream // 將字符轉換為字節,推薦使用 StringReader

1 InputStream類與OutputStream類

InputStream 抽象類中的方法如下:

int read() //讀取一個字節
int read(byte b[]) //最多讀取 b.length 長度的字節,並儲存到數組 b 中,返回實際讀取長度,利用 read() 實現
int read(byte b[], int off, int len) //同上,最多讀取 len 個字節,從 off 開始保存
int available() //返回可以讀取的字節數目,不受阻塞
long skip(long n) //跳過n個字節
void close() //關閉輸入流,並釋放與此流有關的所有資源,未實現,方法體為空
synchronized void mark(int readlimit) //標記當前位置,以便可以使用 reset() 方法復位到該標記的位置
synchronized void reset() //將當前位置復位到上次使用 mark() 方法標記的位置,未實現,調用拋出IO異常
boolean markSupported() //判斷次輸入流是否支持 mark() 和 reset() 方法

OutputStream 抽象類中的方法如下: 

void write(int b) // 抽象的寫入方法
void write(byte b[]) // 寫入一個字節數組,利用 write(int b)實現
void write(byte b[], int off, int len) // 同上
void flush()
void close()

1.1 ByteArrayInputStream類與ByteArrayOutputStream類

ByteArrayInputStream 與 ByteArrayOutputStream 都對“字節數組”的操作,將數據寫入數組、或從數組讀出數據。兩者並無直接關系,都可以單獨使用。

1) ByteArrayInputStream

創建 ByteArrayInputStream 對象時,需要一個“字節數組”,並且會存入其內部的緩沖區 (byte數組) 以待讀取,我們可以通過 read() 方法來獲取。

在 ByteArrayInputStream 內部還有幾個屬性:

  • int pos 當前讀取到的位置
  • int mark 記錄復位的位置
  • int count 帶讀取字符總長度

本類中的方法相對其父類的方法也沒有增加,使用也較為簡單,就不再描述。另外,我們可以利用 ByteArrayInputStream 來讀取 ByteArrayOutputStream 寫入的數據,如下圖

  

2) ByteArrayOutputStream

創建 ByteArrayOutputStream 時,可以指定其內部緩沖區 (byte數組) 的大小 (默認32字節),我們可以通過 wirte() 方法向緩沖區寫入數據,如果緩沖區長度不夠時,會自動擴大至少一倍。

在 ByteArrayOutputStream 內部還有幾個屬性:

  • int count 用來記錄緩沖區的大小
  • static final int MAX_ARRAY_SIZE 緩沖區的最大值

如果需要使用這些數據時我們可以通過 toString() 、toByteArray() 從緩沖區中獲取,也可以通過 writeTo() 將緩沖區數據其寫入其它 OutputStream 類中,如下圖

ByteArrayOutputStream 的部分方法如下:

synchronized void write(int b) // 向緩沖區寫入數據 synchronized void write(byte b[], int off, int len)
synchronized void writeTo(OutputStream out) //將緩沖區數據寫入到其他輸出流中 synchronized void reset() //重置緩沖區 synchronized byte toByteArray()[]synchronized String toString()
synchronized String toString(String charsetName)
synchronized String toString(int hibyte) // @Deprecated 已棄用

 

1.2 FileInputStream類與FileOutputStream類

FileInputStream 與 FileOutputStream 都對“文件”的操作,將數據寫入文件、或從文件讀出數據。兩者並無直接關系,都可以單獨使用。與 ByteArrayInputStream 和 ByteArrayOutputStream 類似,但不同的是一個操作文件,一個操作字符數組。

1) FileInputStream

創建 FileInputStream 對象時,我們可以傳入文件的路徑、對象或者描述符對象。此時會檢查文件是否為空、是否有效、是否可讀 (使用 System.getSecurityManager() 獲取安全管理器來檢查),然后調用本地方法打開文件。

在 FileInputStream 中還有幾個屬性用來描述文件信息:

  • FileDescriptor 文件的描述符
  • String path 存儲了文件的路徑
  • FileChannel

當我們從文件中讀取數據時,FileInputStream 會再去調用本地方法去實現此操作。FileInputStream 部分方法如下:

int read() // 讀取1個字節,如果已經讀完返回-1,調用native read0()來實現,不會阻塞
int read(byte b[]) // 讀取到字節數組中,調用native readBytes()來實現,不會阻塞
int read(byte b[],int off, int len)
native long skip(long n) // 跳過n個字節
native int available() 
FileDescriptor getFD() // 返回表示到文件系統中實際文件的連接的 FileDescriptor 對象。
FileChannel getChannel() // 返回與此文件輸入流有關的唯一FileChannel 對象 
void close() //關閉流,用closeLock變量作為鎖在synchronized代碼塊中改變closed屬性,再調用本地方法關閉
void finalize() // 確保在不再引用文件輸入流時調用其close()方法

2) FileOutputStream

創建 FileOutputStream 對象時,我們可以傳入文件的路徑、對象或者描述符對象,並且可以再傳入一個 boolean 值,判斷是否要以追加的方式寫入。同樣,要判斷文件是否為空、是否有效、是否可寫,然后調用本地方法打開文件。

在 FileOutputStream 中的部分屬性如下:

  • 描述符 FileDescriptor 
  • 路徑
  • FileChannel

當我們向文件中寫入數據時,FileOutputStream 會再去調用本地方法去實現此操作。FileOutputStream 部分方法如下:

void write(int b) // 向文件中寫入一個字節,調用native write()來實現
void write(byte b[]) // 向文件中寫入一個字節數組,調用native writeBytes()來實現
void write(byte b[], int off, int len) // 同上
void close() //關閉流,用closeLock變量作為鎖在synchronized代碼塊中改變closed屬性,再調用本地方法關閉
FileDescriptor getFD()
FileChannel getChannel()
void finalize() //

  

1.3 ObjectInputStream類和ObjectOutputStream類

ObjectInputStream 和 ObjectOutputStream 用於“對象”與“流”之間的轉換,從流中讀出對象或將對象寫入流中(這里的流可能是來自文件,也可能是來自網絡)。另外,該類所讀寫的對象必須實現Serializable接口.

1) ObjectInputStream

創建 ObjectInputStream 對象時,需要傳入一個流(如 FileInputStream),如下圖

在 ObjectInputStrean 中的內部類

  • private static class Caches
  • public static abstract class GetField
  • private class GetFieldImpl extends GetField
  • private static class ValidationList
  • private static class PeekInputStream extends InputStream
  • private class BlockDataInputStream extends InputStream implements DataInput
  • private static class HandleTable

ObjectInputStream 中的部分方法如下

Object readObject()
Object readUnshared()
void defaultReadObject()
ObjectInputStream.GetField readFields()
void registerValidation(ObjectInputValidation obj, int prio)int read()
int read(byte[] buf, int off,int len)
int available()
void close()
boolean readBoolean()
byte readByte()
int readUnsignedByte()
char readChar()
short readShort()
int readUnsignedShort()
int readInt()
long readLong()
float readFloat()
double readDouble()
void readFully(byte[] buf)
void readFully(byte[] buf, int off,int len)
int skipBytes(int len)
public String readUTF()

2) ObjectOutputStream

創建 ObjectOutputStream 對象時,傳入一個流(如 FileOutputStream),如下圖

在 ObjectOutputStream 中的內部類

  • private static class Caches
  • public static abstract class PutField
  • private class PutFieldImpl extends PutField
  • private static class BlockDataOutputStream extends OutputStream implements DataOutput
  • private static class HandleTable
  • private static class ReplaceTable
  • private static class DebugTraceInfoStack

 

1.4 PipedInputStream類與PipedOutputStream類

PipedInputStream 和 PipedOutputStream 的實現原理類似於“生產者-消費者”原理,PipedOutputStream 是生產者,PipedInputStream 是消費者,在 PipedInputStream 中有一個 buffer 字節數組作為緩沖區,默認大小為1024,存放“生產者”生產出來的東西。還有兩個變量 in 和 out,in 是用來記錄“生產者”生產了多少,out 是用來記錄“消費者”消費了多少,in 為-1表示消費完了,in==out 表示生產滿了。當消費者沒東西可消費的時候,也就是當 in 為-1的時候,消費者會一直等待,直到有東西可消費。

PipedInputStream 和 PipedOutputStream 數據傳輸的過程:

  1. 首先兩者要建立一個完整管道,實現方式是“輸入流”調用“輸出流”的 connect() 方法並將自己傳入。在這個方法中“輸出流”拿到了“輸入流”的對象,然后將其傳入 sink 變量,並設置“輸入流”的 connected 屬性為 true。
  2. 建立好完整管道后就可以傳輸數據了,因為剛建立好的管道里並沒有緩存數據,所以首先向管道中寫入數據。我們使用“輸出流”的 write() 方法來寫入數據,在此方法中會調用“輸入流”的 receive() 方法並將數據傳入。如果此時“輸入流”線程在等待狀態,可以調用“輸出流”的 flush() 方法,這個方法中會調用“輸入流”的 notifyAll() 方法將其喚醒。當數據通過“輸入流”的 receive() 方法進入“輸入流”后,將其放入緩沖區中以待讀取。
  3. 當數據寫入到“輸入流”的緩沖區后,“輸入流”就可以使用 read() 方法讀取數據了。當“輸入流”與“輸出流”使用完畢后,應調用雙方的 close() 方法斷開鏈接。

1) PipedInputStream

創建 PipedInputStream 對象時,可以根據 PipedOutputStream 對象來建立一個完整的管道鏈接,並設置緩沖區大小(默認1024)。如果創建對象時不建立連接,那么也要在使用前將鏈接建立好。

我們來看一下部分屬性

  • boolean closedByWriter 與 volatile boolean closedByReader 用來記錄管道是否關閉
  • connected 用來記錄當前管道是否鏈接
  • Thread readSide 與 Thread writeSide;
  • byte buffer[] 緩沖區
  • int in 初始為-1,表示從輸出管道讀出下一個字節后在緩沖區儲存的位置,in==-1表示緩沖區為空,in==out表示緩沖區已滿
  • int out 初始為0,表示從緩沖區讀取下一個字節的位置

PipedInputStream相關方法:

private void initPipe(int pipeSize) //初始化緩沖區
public void connect(PipedOutputStream src) //與輸出管道建立連接
protected synchronized void receive(int b) //接收一個字節的數據,沒有數據輸入則阻塞
synchronized void receive(byte b[], int off, int len) //接收大小為len的數據到數組,不足則阻塞
private void checkStateForReceive() //判斷是否建立連接,讀寫是否已關閉
private void awaitSpace()synchronized void receivedLast() //通知所有等待的線程,最后一個字符已經接收
public synchronized int read() //從緩沖區讀取字節,返回讀取的字節,如果緩沖區沒有數據則會阻塞
public synchronized int read(byte b[], int off, int len) //同上
public synchronized int available()
public void close()

2) PipedOutputStream

創建 PipedOutputStream 對象時,同樣可以傳入一個 PipedInputStream 對象,然后來建立一個完整的管道連接,如果不建立連接,那要在使用前將鏈接建立好。PipedOutputStream 沒有緩存區,寫入的數據會進入到 PipedInputStream 的緩存區中。

PipedOutputStream 只有一個屬性:PipedInputStream sink 用來存放所鏈接的輸入流對象。

PipedOutputStream相關方法:

public synchronized void connect(PipedInputStream snk) // 與輸入流建立連接,需要先獲取到對象鎖
public void write(int b) // 調用連接的輸入流的receive方法,向其寫入一個字節
public void write(byte b[], int off, int len) // 同上,寫入一個字節數組
public synchronized void flush() // 喚醒所連接的輸入流
public void close()

關於 PipedInputStream 和 PipedOutputStream 的幾點要注意:

  • 兩者建立連接時,不能既調用 PipedInputStream 的 connect() 方法又調用 PipedOutputStream 的 connect() 方法,否則會拋出IO異常。且 PipedInputStream 實現 connect() 方法是去調用 PipedOutputStream 的 connect() 方法。
  • 在一個線程里使用 PipedInputStream 和 PipedOutputStream 容易造成卡死(“死鎖”)。例如,當我們調用 PipedOutputStream 的 write() 方法寫入1024字節數據時,該方法通過調用 PipedInputStream 的 receive() 方法將字符數組中的數據寫入到緩沖區,我們在讀取128字節數據后,繼續再向緩沖區寫入1024字節數據,會發現程序卡在寫入數據的這個過程中,造成死鎖。原因是我們第二次向緩沖區寫入數據時,緩沖區滿了,這時候 PipedInputStream 的 awaitSpace() 方法會去執行 notifyAll() 試圖通知 read() 方法去讀取數據,在緩沖區的數據被讀取之前,write() 方法會一直阻塞下去。又因為 PipedInputStream 和 PipedOutputStream 在一個線程里,write() 方法的阻塞導致 read() 方法不能去緩沖區讀取數據,從而形成“死鎖”。

      產生“死鎖”的代碼:                   輸出結果: 

          

 

1.5 FilterInputStream類與FilterOutputStream類及它們的子類

FilterInputStream 與 FilterOutputStream 及子類是使用了裝飾者設計模式。為什么要使用裝飾者設計模式?如果我們覺得某幾個類都缺少一些功能的時候,根據開閉原則,我們不去修改代碼,那我們可以利用繼承對功能進行擴展,但是如果幾個類都需要擴展相同的功能,那么就必須分別對這個幾個類擴展。如果使用裝飾者設計模式,我們就可以解決這個問題。舉個例子,當我們使用 ByteArrayInputStream 的時候只能讀取到以 byte 為單位的數據,我們可以按需要把讀取出來的字節進行轉碼,轉成我們需要的數據,那么能不能直接讀取int、long等數據呢?答案是可以的,我們利用 DataInputStream 類對其進行裝飾即可擁有 readInt()、readLong() 這個方法。

1) FilterInputStream

創建 FilterInputStream 時需要傳入被修飾的輸入流對象,並使用 volatile InputStream in 記錄該對象。FilterInputStream 是所有輸入流修飾類的父類,但其本身並沒有修飾作用,而是直接使用被修飾類的方法,如下是類中的方法

public int read()
public int read(byte b[])
public int read(byte b[], int off, int len)
public long skip(long n)
public int available()
public void close()
public synchronized void mark(int readlimit)
public synchronized void reset()
public boolean markSupported()

2) FilterOutputStream

創建 FilterOutputStream 時需要傳入被修飾的輸出流對象,並使用 OutputStream out 記錄該對象。FilterOutputStream 是所有輸出流修飾類的父類,其本身也沒有修飾作用,如下是類中的方法

public void write(int b)
public void write(byte b[])
public void write(byte b[], int off, int len)
public void flush()
public void close()

 

1.5.1 DataInputStream類與DataOutputStream類

DataInputStream 與 DataOutputStream 是裝飾類,可以對繼承了 InputStream 的類進行裝飾,使其用於讀取或寫入指定類型內容的數據。

1) DataInputStream

創建時需要傳入被包裝的輸入流對象,相關方法如下

public final int read(byte b[]) // 調用被裝飾對象的read()方法
public final int read(byte b[], int off, int len) // 同上
public final void readFully(byte b[]) // 讀取數據到數組,直到存滿,當流中數據不足時,readFully()會阻塞等待
public final void readFully(byte b[], int off, int len) // 同上
public final int skipBytes(int n) // 跳過n個字節
public final boolean readBoolean()
public final byte readByte()
public final int readUnsignedByte()
public final short readShort() // 連續調用read()兩次,然后將結果拼接后強轉short類型,(short)((ch1<<8)+(ch2<<0))
public final int readUnsignedShort() // 同上,但不需要進行強轉
public final char readChar()
public final int readInt()
public final long readLong() // 利用readFully()讀取8個字節到readBuffer數組,然后拼接轉換成long類型
public final float readFloat() // 使用Float.intBitsToFloat(readInt())
public final double readDouble() // 使用Double.longBitsToDouble(readLong())
public final String readLine() // 棄用的
public final String readUTF()
public final static String readUTF(DataInput in) // 待研究

2) DataOutputStream

DataOutputStream 相關方法如下 

private void incCount(int value) // 記錄寫入到流的字節數
public synchronized void write(int b)
public synchronized void write(byte b[], int off, int len)
public void flush() // 讓緩存中的數據傳入到輸入流中
public final void writeBoolean(boolean v)
public final void writeByte(int v)
public final void writeShort(int v)
public final void writeChar(int v) 
public final void writeInt(int v)
public final void writeLong(long v)
public final void writeFloat(float v) //  writeInt(Float.floatToIntBits(v))
public final void writeDouble(double v) // writeLong(Double.doubleToLongBits(v));
public final void writeBytes(String s)
public final void writeChars(String s)
public final void writeUTF(String str)
static int writeUTF(String str, DataOutput out)
public final int size() 

 

1.5.2 BufferedInputStream類與BufferedOutputStream類 

當我們在使用 FileInputStream 和 FileOutputStream 時,要用一個 byte 數組用來接收或寫入數據,硬盤存取的速度遠低於內存中的數據存取速度,為了減少對硬盤的存取,通常從文件中一次讀入一定長度的數據,而寫入時也是一次寫入一定長度的數據,這可以增加文件存取的效率。 

1) BufferedInputStream 

BufferedInputStream 有一個字節數組 buf 作為緩沖區,默認為8192字節。當使用 read() 方法讀取數據時,實際上是先讀取 buf 中的數據,當 buf 中的數據不足時,BufferedInputStream 會再從被裝飾的 InputStream 對象的 read() 方法中讀取數據填滿 buf ,然后再從 buf 中讀取所需大小的數據。如果一次讀取的數據大小超過 buf 緩沖區的大小,則放棄緩沖直接調用被裝飾對象的 read() 方法。

另外,BufferedInputStream 利用原子更新字段類 (AtomicReferenceFieldUpdater) 對緩沖區 volatile byte buf[] 進行包裝。當我們對緩沖區擴容時,得到一個新的緩沖區數組后替換舊的緩沖區數組,此時就要利用原子更新字段類更新。

/*
AtomicReferenceFieldUpdater 位於Atomic包中,是一個基於反射的工具類,它能對指定類的指定的volatile引用字段進行原子更新(注意這個字段不能是private的)。通過靜態方法newUpdater就能創建它的實例,三個參數分別是:包含該字段的對象的類、將被更新的對象的類、將被更新的字段的名稱。
*/
private static final
        AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
        AtomicReferenceFieldUpdater.newUpdater
        (BufferedInputStream.class,  byte[].class, "buf");
protected int count; // 緩沖區內容大小
protected int pos; // 緩沖區當前位置
protected int markpos = -1;
protected int marklimit;
// 該類中的方法:
private InputStream getInIfOpen() // 檢查流是否存在
private byte[] getBufIfOpen() // 檢查緩沖區是否存在
private void fill() // 
public synchronized int read()
private int read1(byte[] b, int off, int len)
public synchronized int read(byte b[], int off, int len)
public synchronized long skip(long n)
public synchronized int available()
public synchronized void mark(int readlimit)
public synchronized void reset()
public boolean markSupported()
public void close()

2) BufferedOutputStream

BufferedOutputStream 也有一個字節數組 buf 作為緩沖區,默認同樣為8192字節,並用一個變量 count 記錄緩沖區內數據大小。當使用 write() 方法寫入數據時,實際上會先將數據寫至 buf 中,當 buf 已滿時,BufferedOutputStream 才會利用被裝飾的 OutputStream 對象的 write() 方法寫入數據。如果一次寫入的數據大小超過 buf 緩沖區的大小,則放棄緩沖直接調用被裝飾對象的 write() 方法。

BufferedOutputStream 的相關方法如下

private void flushBuffer() // 將緩沖區的數據寫入流,調用了被裝飾對象的write方法
public synchronized void write(int b) // 將數據寫入緩沖,如果緩沖滿了,調用flushBuffer()方法
public synchronized void write(byte b[], int off, int len) // 同上
public synchronized void flush() 

 

1.5.3 PushbackInputStream類

對輸入流進行裝飾,可以將當前讀取的字節數據推回到緩存區,一般用不到的。

// 該類中的屬性:
protected byte[] buf;
protected int pos;
// 該類中的方法:
private void ensureOpen()
public int read()
public int read(byte[] b, int off, int len)
public void unread(int b)
public void unread(byte[] b, int off, int len)
public void unread(byte[] b)
public int available()
public long skip(long n)
public boolean markSupported() // 不支持mark功能
public synchronized void mark(int readlimit)
public synchronized void reset()
public synchronized void close()

 

1.5.4 LineNumberInputStream類

對輸入流進行裝飾,可以獲取輸入流的行數或設置行數,已過時。已經被LineNumberReader替代。

 

1.5.5 PrintStream類

對輸出流進行裝飾,

// 構造方法:
private PrintStream(boolean autoFlush, OutputStream out) // 傳入一個需裝飾的對象
private PrintStream(boolean autoFlush, OutputStream out, Charset charset)
private PrintStream(boolean autoFlush, Charset charset, OutputStream out)
public PrintStream(OutputStream out)
public PrintStream(OutputStream out, boolean autoFlush) 
public PrintStream(OutputStream out, boolean autoFlush, String encoding)
public PrintStream(String fileName)
public PrintStream(String fileName, String csn)
public PrintStream(File file)
public PrintStream(File file, String csn)
// 該類中的屬性:
private final boolean autoFlush;
private boolean trouble = false;
private Formatter formatter;
private BufferedWriter textOut;
private OutputStreamWriter charOut;
private boolean closing = false;
// 該類中的方法:
private static <T> T requireNonNull(T obj, String message)
private static Charset toCharset(String csn)
private void ensureOpen()
public void flush()
public void close()
public boolean checkError() 
protected void setError()
protected void clearError()
public void write(int b)
public void write(byte buf[], int off, int len)
private void write(char buf[])
private void write(String s)
private void newLine() 
public void print(boolean b)
public void print(char c)
public void print(int i)
public void print(long l)
public void print(float f)
public void print(double d) 
public void print(char s[])
public void print(String s) 
public void print(Object obj)
public void println()
public void println(boolean x)
public void println(char x)
public void println(int x)
public void println(long x)
public void println(float x)
public void println(double x)
public void println(char x[]) 
public void println(String x)
public void println(Object x) 
public PrintStream printf(String format, Object ... args)
public PrintStream printf(Locale l, String format, Object ... args)
public PrintStream format(String format, Object ... args)
public PrintStream format(Locale l, String format, Object ... args)
public PrintStream append(CharSequence csq)
public PrintStream append(CharSequence csq, int start, int end)
public PrintStream append(char c)

 

1.6 StringBufferInputStream類

已經不再適合將字符轉化為字節,更優的選擇是通過StringReader將字符轉化為流。

 

1.7 SequenceInputStream類

// 構造方法:
public SequenceInputStream(Enumeration<? extends InputStream> e)
public SequenceInputStream(InputStream s1, InputStream s2)
// 該類中的屬性:
Enumeration<? extends InputStream> e
InputStream in;
// 該類中的方法:
final void nextStream()
public int available()
public int read()
public int read(byte b[], int off, int len)
public void close() 

 

 

二、Reader類與Writer類

在字符流的類中,最頂層的是 Reader 抽象類和 Writer 抽象類,兩者定義了一些關於字符數據讀寫的基本操作。他們的實現類有

  • CharArrayReader/CharArrayWriter
  • StringReader/StringWriter
  • InputStreamReader/OutputStreamWriter
    • FileReader/FileWriter
  • PipedReader/PipedWriter
  • FilterReader/FilterWriter
    • PushbackReader
  • BufferedReader/BufferedWriter
    • LineNumberReader
  • PrintWriter 

2、Reader類與Writer類及它們的子類

Reader抽象類中的方法如下:

// 構造方法
protected Reader()
protected Reader(Object lock)
// 該類中的屬性
protected Object lock;
private static final int maxSkipBufferSize = 8192;
private char skipBuffer[] = null;
// 該類中的方法
public int read(java.nio.CharBuffer target)
public int read() 
public int read(char cbuf[])
abstract public int read(char cbuf[], int off, int len)
public long skip(long n)
public boolean ready() 
public boolean markSupported()
public void mark(int readAheadLimit)
public void reset()
abstract public void close()

Writer抽象類中的方法如下:

// 構造方法
protected Writer()
protected Writer(Object lock)
// 該類中的屬性
private char[] writeBuffer;
private static final int WRITE_BUFFER_SIZE = 1024;
protected Object lock;
// 該類中的方法
public void write(int c)
public void write(char cbuf[])
abstract public void write(char cbuf[], int off, int len)
public void write(String str)
public void write(String str, int off, int len)
public Writer append(CharSequence csq)
public Writer append(CharSequence csq, int start, int end)
public Writer append(char c)
abstract public void flush()
abstract public void close()

 

2.1 CharArrayReader類與CharArrayWriter類

CharArrayReader 與 CharArrayWriter,並無直接關系,兩者都可以單獨使用。

CharArrayReader相關方法:

// 構造方法
public CharArrayReader(char buf[]) 
public CharArrayReader(char buf[], int offset, int length)
// 該類中的屬性
protected char buf[]; // 緩沖區
protected int pos; // 緩沖區使用位置
protected int markedPos = 0;
protected int count;
// 該類中的方法
private void ensureOpen() // 如果流關閉,則拋出IO異常
public int read() // 讀一個字符,返回,若流中數據已讀完則返回-1
public int read(char b[], int off, int len)
public long skip(long n)
public boolean ready() // 判斷是否已經可以從流中讀數據
public boolean markSupported()
public void mark(int readAheadLimit)
public void reset()
public void close() 

CharArrayWriter相關方法:

// 構造方法
public CharArrayWriter() // 緩沖區默認32
public CharArrayWriter(int initialSize)
// 該類中的屬性
protected char buf[]; // 緩沖區
protected int count;
// 該類中的方法
public void write(int c)
public void write(char c[], int off, int len) 
public void write(String str, int off, int len)
public void writeTo(Writer out) // 將緩沖區的內容寫入到另一個字符流
public CharArrayWriter append(CharSequence csq) //
public CharArrayWriter append(CharSequence csq, int start, int end) //
public CharArrayWriter append(char c) //
public void reset()
public char toCharArray()[]
public int size()
public String toString()
public void flush()
public void close()

 

2.2 StringReader類與StringWriter類

與CharArrayReader 與 CharArrayWriter 相似

StringReader相關方法:

// 構造方法
public StringReader(String s)// 該類中的屬性
private String str;
private int length;
private int next = 0;
private int mark = 0;
// 該類中的方法
private void ensureOpen()
public int read()
public int read(char cbuf[], int off, int len)
public long skip(long ns)
public boolean ready()
public boolean markSupported()
public void mark(int readAheadLimit)
public void reset()
public void close()

StringWriter相關方法(就是把StringBuffer封裝了一下):

// 構造方法
public StringWriter()
public StringWriter(int initialSize)
// 該類中的屬性
private StringBuffer buf;
// 該類中的方法
public void write(int c)
public void write(char cbuf[], int off, int len)
public void write(String str)
public void write(String str, int off, int len)
public StringWriter append(CharSequence csq)
public StringWriter append(CharSequence csq, int start, int end)
public StringWriter append(char c)
public String toString()
public StringBuffer getBuffer()
public void flush() 
public void close()

 

2.3 PipedReader類與PipedWriter類

PipedReader 與 PipedWriter 的使用和 PipedInputStream 與 PipedOutputStream 十分相似,原理也相同。

PipedReader相關方法:

// 構造方法
public PipedReader(PipedWriter src) 
public PipedReader(PipedWriter src, int pipeSize)
public PipedReader()
public PipedReader(int pipeSize)
// 該類中的屬性
boolean closedByWriter = false;
boolean closedByReader = false;
boolean connected = false;
Thread readSide;
Thread writeSide;
private static final int DEFAULT_PIPE_SIZE = 1024;
char buffer[];
int in = -1;
int out = 0;
// 該類中的方法
private void initPipe(int pipeSize)
public void connect(PipedWriter src)
synchronized void receive(int c)
synchronized void receive(char c[], int off, int len) 
synchronized void receivedLast()
public synchronized int read() 
public synchronized int read(char cbuf[], int off, int len) 
public synchronized boolean ready()
public void close()

PipedWriter相關方法:

// 構造方法
public PipedWriter(PipedReader snk)
public PipedWriter()
// 該類中的屬性
private PipedReader sink;
private boolean closed = false;
// 該類中的方法
public synchronized void connect(PipedReader snk)
public void write(int c)
public void write(char cbuf[], int off, int len)
public synchronized void flush()
public void close()

 

2.4 InputStreamReader類與OutputStreamWriter類

InputStreamReader 與 OutputStreamWriter 使用的是適配器模式,作為字節流與字符流兩個不兼容的類(接口)之間的橋梁。以 InputStreamReader 為例,InputStreamReader 繼承了 Reader 抽象類,利用 InputStream 對象(這個對象是由構造方法傳來的)的方法,對 Reader 抽象類的方法進行實現(實現的時候是利用 StreamDecoder 進行轉碼),從而使字節流轉換成字符流。

InputStreamReader相關方法:

// 構造方法
public InputStreamReader(InputStream in)
public InputStreamReader(InputStream in, String charsetName)
public InputStreamReader(InputStream in, Charset cs) 
public InputStreamReader(InputStream in, CharsetDecoder dec)
// 該類中的屬性
private final StreamDecoder sd;
// 該類中的方法
public String getEncoding() 
public int read()
public int read(char cbuf[], int offset, int length)
public boolean ready() 
public void close()

OutputStreamWriter相關方法:

// 構造方法
public OutputStreamWriter(OutputStream out, String charsetName)
public OutputStreamWriter(OutputStream out)
public OutputStreamWriter(OutputStream out, Charset cs)
public OutputStreamWriter(OutputStream out, CharsetEncoder enc) 
// 該類中的屬性
private final StreamEncoder se;
// 該類中的方法
public String getEncoding()
void flushBuffer()
public void write(int c)
public void write(char cbuf[], int off, int len)
public void write(String str, int off, int len) 
public void flush()
public void close()

 

2.4.1 FileReader類和FileWriter類

兩者都是在構造方法中創建對應的 FileInputStream 或 FileOutputStream對象,然后將調用父構造方法將其傳入。

public FileReader(String fileName) 
public FileReader(File file)
public FileReader(FileDescriptor fd) 
public FileWriter(String fileName)
public FileWriter(String fileName, boolean append)
public FileWriter(File file) 
public FileWriter(File file, boolean append)
public FileWriter(FileDescriptor fd)

 

2.5 FilterReader類和FilterWriter類

FilterReader相關方法:

// 構造方法
protected FilterReader(Reader in)
// 該類中的屬性
protected Reader in; // 需要裝飾的對象 
// 該類中的方法
public int read()
public int read(char cbuf[], int off, int len)
public long skip(long n)
public boolean ready()
public boolean markSupported()
public void mark(int readAheadLimit)
public void reset()
public void close()

FilterWriter相關方法:

// 構造方法
protected FilterWriter(Writer out)
// 該類中的屬性
protected Writer out; // 需要裝飾的對象 
// 該類中的方法
public void write(int c)
public void write(char cbuf[], int off, int len)
public void write(String str, int off, int len) 
public void flush() 
public void close()

 

2.5.1 PushbackReader類

// 構造方法
public PushbackReader(Reader in, int size)
public PushbackReader(Reader in)
// 該類中的屬性
private char[] buf;
private int pos;
// 該類中的方法
private void ensureOpen() 
public int read() 
public int read(char cbuf[], int off, int len)
public void unread(int c)
public void unread(char cbuf[], int off, int len)
public void unread(char cbuf[]) 
public boolean ready()
public void mark(int readAheadLimit) 
public void reset() 
public boolean markSupported()
public void close()
public long skip(long n)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM