Java I/O之InputStream和OutputStream(一)

InputStream:字節輸入流的所有類的父類

OutputStream:字節輸出流的所有類的父類

這裏的輸入和輸出是針對內存說的,一般來說,向內存讀入數據爲輸入,從內存讀出爲輸出。

下邊是對兩個類的源碼分析:

InputStream.java

package java.io;

/**
 * 字節輸入流的所有類的超類
 * 1. Closeable:實現close方法,可以在try-with-resource中自動關閉資源
 */
public abstract class InputStream implements Closeable {

  // 在skip方法中使用
  private static final int MAX_SKIP_BUFFER_SIZE = 2048;

  /**
   * 1. 讀取輸入流數據的下一個字節,返回這個字節的int值,一個字節能表示的大小爲0-255,
   *    所以這個方法的(正確)返回值範圍是0-255。
   * 2. 如果該輸入流到達末尾處,沒有可用的字節來讀取,那麼返回-1。
   * 3. 該方法會阻塞,直到 1)有輸入數據可用 2)到達流的末尾 3)有異常拋出。
   * 4. 子類必須實現該方法
   */
  public abstract int read() throws IOException;

  /**
   * 1. 讀取輸入流中若干(不是一個了,效率提升)字節並且將它們存儲在緩衝數組中,返回實際讀到的字節數量。
   * 2. 該方法同樣會阻塞,直到 1)有輸入數據可用 2)到達流的末尾 3)有異常拋出。
   * 3. 如果緩衝數組的長度爲0,那麼返回0;否則至少讀取一個字節。
   *    如果讀到流的末尾,返回讀取的字節數。
   * 4. 第一個讀取的字節存儲在b[0],下一個存儲在b[1],依次類推。讀取到的字節數量最多等於b數組的長度。假設
   *    k是實際讀取到的字節數量,這些字節將被存儲到b[0]-b[k-1]中,b[k]-b[b.length-1]的元素不受影響。這裏
   *    的不受影響是什麼意思呢??
   */
  public int read(byte b[]) throws IOException {
      return read(b, 0, b.length);
  }

  /**
   * 1. 從輸入流中讀取len個字節到字節數組中,儘可能的讀取len個字節,但是可能少於len個字節。返回實際讀取到的字節數。
   *    如果len=0,那麼沒有數據可讀,返回0。
   * 2. 第一個讀取的字節存儲在b[off]中,依次類推。最多讀len個字節。
   */
  public int read(byte b[], int off, int len) throws IOException {
      // 如果緩衝數組爲null,則拋出 NullPointerException
      if (b == null) {
          throw new NullPointerException();
      } else if (off < 0 || len < 0 || len > b.length - off) { 
          // 1. 如果數組存儲數據的開始位置小於0,IndexOutOfBoundsException
          // 2. 如果設置的讀取字節長度小於0,IndexOutOfBoundsException
          // 3. 如果數組偏移後的剩餘長度不足len,IndexOutOfBoundsException
          throw new IndexOutOfBoundsException();
      } else if (len == 0) {
          // 如果len=0,返回0,什麼也不做
          return 0;
      }

      int c = read();
      // 如果讀到的字節爲-1,說明到達流的末尾,返回-1
      if (c == -1) {
          return -1;
      }
      // 將讀取的第一個字節存入b[off]
      b[off] = (byte)c;

      // i表示讀取到的字節數
      int i = 1;
      try {
          for (; i < len ; i++) {
              c = read();
              // 讀到流末尾處,終止循環
              if (c == -1) {
                  break;
              }
              b[off + i] = (byte)c;
          }
      } catch (IOException ee) {
      }
      return i;
  }

  // n 表示傳入需要跳過的字節數
  // 返回實際跳過的字節數
  // 1. 當輸入流的數據大於n時,且 n<MAX_SKIP_BUFFER_SIZE時,則一次就可跳過n
  // 2. 當輸入流的數據大於n時,且 n>MAX_SKIP_BUFFER_SIZE時,則一次只能讀取MAX_SKIP_BUFFER_SIZE個,最後一次讀取
  //    n%MAX_SKIP_BUFFER_SIZE個
  // 3. 當輸入流的數據小於n時,且 n<MAX_SKIP_BUFFER_SIZE時,則一次就可跳過整個輸入流,不是n
  // 還有其它場景,原理大致一樣
  public long skip(long n) throws IOException {

      // 記錄每循環一次讀取,剩餘需要跳過的字節數
      long remaining = n;
      // 記錄每次循環跳過的字節數
      int nr;

      // n 需要大於0,否則沒有意義
      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;
      }
      // 返回實際跳過的字節數,其實nr纔是統計每次跳過的字節數的變量,原理是 remianing(最終的) = remaining(其實就是n)-(nr1+nr2+nr3+...),
      // 返回 n-remianing = nr1+nr2+nr3+...
      return n - remaining;
  }

  public int available() throws IOException {
      return 0;
  }

  public void close() throws IOException {}

  /**
   * mark和reset方法一起使用,mark表示標記某個reset恢復的位置
   */
  public synchronized void mark(int readlimit) {}

  public synchronized void reset() throws IOException {
      throw new IOException("mark/reset not supported");
  }
  
  /*
   * 是否支持mark和reset方法
   */
  public boolean markSupported() {
      return false;
  }
}

 OutputStream.java

package java.io;

/**
 * 字節輸出流的超類,接收字節並將其發送到某個接收器
 * 實現兩個重要的接口:
 * 1. Closeable:實現close方法,可以在try-with-resource中自動關閉資源
 * 2. Flushable:實現flush方法,可以操作底層刷新流
 */
public abstract class OutputStream implements Closeable, Flushable {
	
	/*
	 * 子類必須實現的方法
	 */
    public abstract void write(int b) throws IOException;

    public void write(byte b[]) throws IOException {
        write(b, 0, b.length);
    }

    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]);
        }
    }

    public void flush() throws IOException {
    }

    public void close() throws IOException {
    }

}

 

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