1. 程式人生 > 其它 >Java IO (二)抽象基類InputStream、OutputStream、Reader、Writer

Java IO (二)抽象基類InputStream、OutputStream、Reader、Writer

2、抽象基類InputStream、OutputStream、Reader、Writer

IO流的抽象基類分位元組輸入流(InputStream)、位元組輸出流(OutputStream)、字元輸入流(Reader)、字元輸出流(Writer)。它們是IO流中的抽象父類,是Java IO操作的基礎。流都實現了Closeable介面,即都需要關閉,輸出流則額外實現了一個Flushable方法,主要是通知立刻將資料刷入指定輸出位置。

2.1 InputStream

java.io.InputStream是一個抽象類,是位元組輸入流的所有類的超類,除了繼承自Object的屬性和方法,InputStream包含9個方法:

  1. abstract int read()方法是一個虛擬方法,從輸入流中讀取下一個位元組,其子類必須實現這個方法

  2. int read(byte[] b,int off,int len)方法將流讀入byte[]陣列中第off個位置開始,讀取len個位元組。其實現有呼叫read()方法進行讀取,讀取前判斷引數是否合理,若讀取到-1則退出(流以-1判斷是否結束),並返回已經讀取的資料個數,若讀取的個數為0則返回-1。

    public int read(byte b[], int off, int len) throws IOException {
            if (b == null) {
                
    throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } ​ int c = read(); if (c == -1) { return -1; } b[off]
    = (byte)c; ​ int i = 1; try { for (; i < len ; i++) { c = read(); if (c == -1) { break; } b[off + i] = (byte)c; } } catch (IOException ee) { } return i; }

  3. int read(byte[])方法用處是將流的輸入讀入byte[]陣列中,其實際上呼叫的是read(byte[],int,int)

  4. long skip(long),跳過指定個位元組不讀。其具體實現是:建立了一個跳過的緩衝資料,將讀到這裡面去,跳過的位元組有長度限制,為2048個。通過迴圈排除IO異常的感染,知道讀完或者讀滿要跳過的,然後返回實際跳過的量。

     
     public long skip(long n) throws IOException {
    ​
            long remaining = n;
            int nr;
    ​
            if (n <= 0) {
                return 0;
            }
    ​
            int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
            byte[] skipBuffer = new byte[size];
            while (remaining > 0) {
                nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
                if (nr < 0) {
                    break;
                }
                remaining -= nr;
            }
    ​
            return n - remaining;
        }
  5. int available()返回估測的可讀的數量,在InputStream中是直接return 0。這個方法對於所有流的實現來說不都是準確的,所以慎用。這個方法需要被子類覆寫。單次讀或跳過很多位元組不會阻塞,但是可能會讀取或跳過少量位元組。

  6. void close(),關閉流,但是在InputStream中沒有具體實現,會釋放作業系統資源。

  7. synchronized void mark(int readlimit)標記讀取位置,如果流實現支援,就可以重置位置,下次讀取則一模一樣。InputStream中什麼都沒做。使用之前要通過markSupported方法判斷一下是否支援。

  8. synchronized void reset()reset到mark方法最後一次呼叫的位置,InputStream中並沒有實現mark方法,所以reset方法直接丟擲異常。

  9. boolean markSupported()判斷當前流是否支援標記流。

2.2 OutputStream

java.io.OutputStream此抽象類是表示輸出位元組流的所有類的超累,輸出流接受輸出位元組並將這些位元組傳送到某個接收器,除了繼承自Object的屬性和方法,OutputStream包含5個方法:

  1. abstract void write(int b),抽象方法,通常是寫入一個位元組byte,低8位將寫入,高24位會被忽略。將指定位元組寫入輸出位置,子類必須實現這個方法。

  2. void write(byte b[], int off, int len)方法,將陣列b的起始位置off開始,寫入len長度的位元組。其實現包含邊界判定,最後通過迴圈呼叫write方法實現。

      
    public void write(byte b[], int off, int len) throws IOException {
            if (b == null) {
                throw new NullPointerException();
            } else if ((off < 0) || (off > b.length) || (len < 0) ||
                       ((off + len) > b.length) || ((off + len) < 0)) {
                throw new IndexOutOfBoundsException();
            } else if (len == 0) {
                return;
            }
            for (int i = 0 ; i < len ; i++) {
                write(b[off + i]);
            }
        }

  3. void write(byte b[])通過呼叫方法2:write(b,0,b.length)實現

  4. void flush()重新整理此輸出流並強制攜出所有緩衝的輸出位元組。flush的常規協定是:如果此輸出流的實現已經緩衝了以前寫入的任何位元組,則呼叫flush方法指示應將這些位元組立即寫入它們的預期目標。但是如果此流的預期目標是由基礎作業系統提供的一個抽象(如一個檔案),則flush只能保證將以前寫入到流的位元組傳遞給作業系統進行寫入,不保證能立即將這些位元組寫入到物理裝置(如磁碟驅動器)。在OutputStream中該方法不執行任何操作。

  5. void close()關閉輸出流並釋放與此流有關的所有系統資源。close的常規協定是:該方法將關閉輸出流,關閉的流不能執行輸出操作,也不能重新發開。OutputStream的close方法不執行人格操作。

2.3 Reader

java.io.Reader實現了介面Closeable和Readable,其是用於讀取字元流的抽象類。

相比於位元組輸入流InputStream,Reader中不同的有以下幾點:

  1. lock物件 lock是Object型別的物件,用於同步針對此流的操作的物件。為了提高效率,字元流可以使用自身以外的物件來保護重要部分,因此,子類應使用此欄位中的物件而不是this或者同步的方法。構造方法中Reader()所做的是建立一個新的字元流,其重要部分將同步其自身的reader;而Reader(Object lock)則是建立一個新的字元流reader,其重要部分將同步給定的物件。

  2. Reader的三個read方法中,read()方法和read(char cbuf[])都是使用read(char cbuf[], int off, int len)實現的,而子類必須實現read(char cbuf[], int off, int len)方法,注意:用於支援高效單字元輸入的子類必須重寫read()方法

       /*用於支援高效單字元輸入的子類必須重寫該方法*/
       public int read() throws IOException {
            char cb[] = new char[1];
            if (read(cb, 0, 1) == -1)
                return -1;
            else
                return cb[0];
        }
    ​
        public int read(char cbuf[]) throws IOException {
            return read(cbuf, 0, cbuf.length);
        }
    ​
        /*子類必須實現該方法*/
        abstract public int read(char cbuf[], int off, int len) throws IOException;

  3. read(CharBuffer target)方法:該方法試圖將字元讀入指定的字元緩衝區。緩衝區可照鴛鴦用作字元的儲存庫:所做的唯一改變時put操作的結果。不對緩衝區執行翻轉或重繞操作。

     
     public int read(java.nio.CharBuffer target) throws IOException {
            int len = target.remaining();
            char[] cbuf = new char[len];
            int n = read(cbuf, 0, len);
            if (n > 0)
                target.put(cbuf, 0, n);
            return n;
        }

  4. *ready()方法** 該方法在Reader中是直接返回flase的,其用來判斷是否準備讀取此流。如果保證下一個read()不阻塞輸入,則返回True,否則返回false。注意,返回false並不保證下一次讀取。

  5. skip()方法的長度限制是8192

2.4 Writer

java.io.Writer實現了Closeable, Flushable, Appendable三個介面,它時寫入字元流的抽象類。

Appendable:如果某個類的例項打算接收取自 Formatter 的格式化輸出,那麼該類必須實現 Appendable 介面。

Writer相比於位元組輸出流OutputStream有更多的不同。

  1. lock物件

  2. write方法 Writer提供了5個write方法,其中子類需要實現的是void write(char cbuf[], int off, int len)

    /*該方法使用write(char cbuf[], int off, int len)方法實現*/
     public void write(int c) throws IOException {
          synchronized (lock) {
              if (writeBuffer == null){
                  writeBuffer = new char[WRITE_BUFFER_SIZE];
              }
              writeBuffer[0] = (char) c;
              write(writeBuffer, 0, 1);
          }
      }
      /*該方法使用write(char cbuf[], int off, int len)方法實現*/
      public void write(char cbuf[]) throws IOException {
          write(cbuf, 0, cbuf.length);
      }
    ​
      /*子類必須實現該方法*/
      abstract public void write(char cbuf[], int off, int len) throws IOException;
      /*該方法使用write(String str, int off, int len)方法實現*/
      public void write(String str) throws IOException {
          write(str, 0, str.length());
      }
    ​
      /*該方法使用write(char cbuf[], int off, int len)方法實現*/
      public void write(String str, int off, int len) throws IOException {
          synchronized (lock) {
              char cbuf[];
              if (len <= WRITE_BUFFER_SIZE) {
                  if (writeBuffer == null) {
                      writeBuffer = new char[WRITE_BUFFER_SIZE];
                  }
                  cbuf = writeBuffer;
              } else {    // Don't permanently allocate very large buffers.
                  cbuf = new char[len];
              }
              str.getChars(off, (off + len), cbuf, 0);
              write(cbuf, 0, len);
          }
      }
    3.append方法都來自於其實現的Appendable介面,用於將指定字元或字元序列新增到此writer。
  3.    public Writer append(CharSequence csq) throws IOException {
            if (csq == null)
                write("null");
            else
                write(csq.toString());
            return this;
        }
    ​
        
        public Writer append(CharSequence csq, int start, int end) throws IOException {
            CharSequence cs = (csq == null ? "null" : csq);
            write(cs.subSequence(start, end).toString());
            return this;
        }
    ​
       
        public Writer append(char c) throws IOException {
            write(c);
            return this;
        }