認知IO流之 — InputStream

關注公衆號回覆002,有你想要的一切

640?wx_fmt=jpeg

這是 cxuan 的第 34 篇原創文章

InputStream 結構概述

InputStream 是一個抽象類,這個抽象類是代表所有字節流輸入的父類,應用程序需要定義一個InputStream 的子類,該子類需要提供一個返回下一個輸入字節的方法。

下面是 InputStream 的繼承體系:

640?wx_fmt=png

下面是針對 InputStream 的子類做的圖表,從圖表中可以對 InputStream 的子類有一個大致的瞭解

類和功能構造器參數解釋
FileInputStream 用於從文件系統的文件中讀取字節。字符串,表示文件名,文件或 FileDescriptor 對象
FilterInputStream 包含一些其他的輸入流,並將其作爲基本的數據源,提供數據轉換和其他功能InputStream 類型,包含其任意子類
ObjectInputStream 是將對象的原始數據序列化的輸入流一個可以接收InputStream 類型的構造函數,一個包級私有的無參構造函數
PipedInputStream 管道輸入流提供寫入管道輸出流的任何數據字節,實現管道化的概念PipedOutputStream管道輸出流,也可控制管道容量的大小
SequenceInputStream 將兩個或者多個InputStream 轉換成單一 InputStream兩個InputStream 對象或一個容納 InputStream 對象的容器 Enumeration
ByteArrayInputStream 允許內存的緩衝區當作 InputStream 使用緩衝區,從緩衝區取出字節

InputStream 特性

InputStream 中有一個常量 MAX_SKIP_BUFFER_SIZE,它用來確定最大能夠跳過的字節緩衝,主要用於 skip() 方法

private static final int MAX_SKIP_BUFFER_SIZE = 2048;

read 方法

作爲一個抽象類,InputStream 必須至少有一個抽象方法纔可以,這個唯一的抽象方法就是 read()方法

public abstract int read() throws IOException;

read() 方法表示從輸入流讀取下一個字節的數據,byte字節的值作爲 int 返回,其範圍在0 - 255 之間。如果到達流的末尾而沒有可用的字節的話,則返回 -1, 一般用 -1 來判斷字節流是否到了末尾。此方法會被鎖住直到有輸入數據的時候,這種 IO 流也叫做 BIO阻塞IO,它的效率比較低。子類必須提供此方法的實現。

另外一個同名方法也是 read() 方法,不過這個方法不是抽象方法

public int read(byte b[]) throws IOException {
  return read(b, 0, b.length);
}

從輸入流中讀取一定數量的字節並把它們存儲在緩衝數組中。實際讀取的字節數以整數形式返回。如果參數 b 的長度是0 ,就不會讀取字節並且返回 0;這個方法會嘗試讀取至少一個字節並存儲在b數組中。第一個讀取並存儲的字節是 b[0],下一個是 b[1],以此類推。讀取的字節最多等於 b數組的長度。

這個方法會調用 read(b, 0, b.length) 方法,來看一下此方法的定義

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

如果沒有可讀取的數組,直接拋出空指針異常,如果起始讀取位置小於0,或者讀取長度小於0,或者需要讀取的長度要比實際的長度大,拋出數組越界異常,若讀取的長度爲0,那麼就不會讀取任何字節。上面代碼調用的 read() 無參數的方法交給子類去實現,如果子類讀取到了 -1 ,那麼就直接返回 -1。

skip 方法

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

跳過並丟棄此輸入流中的字節數據。由於各種原因,skip 方法最終可能會跳過一些較小的字節數,可能是0。這可能是由許多條件中的任何一個引起的;只有一種可能性就是在跳過 n 個字節之前到達末尾。此方法會返回跳過的實際字節數。如果 n 是負數,skip 方法總是返回 0,並且不跳過任何字節。

available 方法

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

返回下一個方法調用能不受阻塞地從此讀取(或者跳過)的估計字節數。注意,InputStream 的某些實現將返回流中的總字節數,但是許多實現則不會。

如果輸入流通過調用 close() 方法關閉後,此方法的子類實現還會拋出 IOException。InputStream 類的 available 方法總是返回 0 。

close 方法

public void close() throws IOException {}

關閉這個輸入流並且釋放流分配的系統資源。InputStream 的 close 方法不做任何操作。

mark 方法

public synchronized void mark(int readlimit) {}

用於標記輸入流當前的位置。隨後對 reset 方法的調用會在最後標記的位置處重新定位此流的位置以便後續重新讀取相同的字節。

readlimit 參數會告訴輸入流允許在標記位置失效之前讀取多個字節。

mark 方法的一般約定是,如果方法 markSupported 返回 true,那麼在調用mark方法後,流會以某種方式記錄所有讀取的字節。當調用reset方法後,能夠再次提供同樣的字節。但是,在調用reset之前,流不會記錄readlimit以外的字節。在已經關閉的流上調用mark方法對流沒有影響

InputStream 的 mark 方法不會做任何事情。

reset 方法

public synchronized void reset() throws IOException {
  throw new IOException("mark/reset not supported");
}

將此流重新定位到上次在此輸入流上調用 mark 方法的位置。

reset 的一般規定是如果 markSupported 方法返回 true,則

自從流被創建後如果沒有調用 mark 方法,或者 mark方法從最後一次調用後從流中讀取的字節數量要大於最後一次調用時 mark 的參數的話,可能拋出 IOException。

如果沒有拋出 IOException 的話,這時流會重置爲一種狀態,這時從最近一次調用 mark 以來所讀取的所有字節將被提供給 read 方法的後續調用者。

如果 markSupported 返回 false,則這個 reset 調用可能拋出 IOException,如果沒有拋出 IOException 的話,則將流重置爲固定狀態,該狀態取決於輸入流的特定類型及其創建方式。

markSupported 方法

public boolean markSupported() {
  return false;
}

markSupported 方法就是一個判斷是否支持 mark 和 reset 方法的標示。返回 true 表示支持,默認是 false。

相關閱讀

                
就是要讓你徹底學會 @Bean 註解
我賭你不清楚Spring中關於Null的這些事
我被面試官給虐懵了,竟然是因爲我不懂Spring中的@Configuration
一文了解那些和Spring Bean有關的註解!
Resource 體系介紹
深究Spring中Bean的生命週期

640?wx_fmt=png
你點的每個好看,我都認真當成了喜歡

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