輸入流InputStream的reset()和mark()方法注意事項

InputStream的reset方法失敗,然後查了一下JDK源碼,發現BufferInputStream重寫了父類FilterInputStream的mark和resetf方法,其有支持 mark 和 reset 方法的能力。而FileInputStream則沒有重寫父類InputStream的這兩個方法,其不具有mark和reset方法的能力。

在JDK源碼中,寫到

        public synchronized void mark(int readlimit)

            在該輸入流中標記當前位置。 後續調用 reset 方法重新將流定位於最後標記位置,以便後續讀取能重新讀取相同字節。

          readlimit 參數給出當前輸入流在標記位置變爲非法前允許讀取的字節數。

          這句話的意思是說:mark就像書籤一樣,用於標記,以後再調用reset時就可以再回到這個mark過的地方。mark方法有個參數,通過這個整型參數,你告訴系統,希望在讀出這麼多個字符之前,這個mark保持有效。比如說mark(10),那麼在read()10個以內的字符時,reset()操作後可以重新讀取已經讀出的數據,如果已經讀取的數據超過10個,那reset()操作後,就不能正確讀取以前的數據了,因爲此時mark標記已經失效。   

  下面是BufferInputStream以及父類FilterInputStream 中這兩個方法的默認實現

//FilterInputStream.java 

 public synchronized void mark(int readlimit) {

    in.mark(readlimit);

    }

 

 public synchronized void reset() throws IOException {

    in.reset();

    }

<br>public boolean markSupported() {<br>    return in.markSupported()<br>}

 

//BufferedInputStream.java

    public synchronized void mark(int readlimit) {

    marklimit = readlimit;

    markpos = pos;

    }

 

  public synchronized void reset() throws IOException {

        getBufIfOpen(); // Cause exception if closed

    if (markpos < 0)

        throw new IOException("Resetting to invalid mark");

    pos = markpos;

    }<br><br>

 public boolean markSupported() {
    return true;
    } //支持mark操作

  而FileInputStream沒有重寫父類InputStream的默認實現,其默認實現如下:

 

//InputStream.java
  public synchronized void mark(int readlimit) {}//空實現什麼都沒有實現

public synchronized void reset() throws IOException {
    throw new IOException("mark/reset not supported");
    }//不支持reset操作

 public boolean markSupported() {
    return false;
    } //不支持mark操作

 

    下面是一個簡單的程序,用於設置reset和mark.

 


import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;


public class TestInputStream {

public void read(InputStream in) throws IOException {
 if(in == null) {
 return;
 }
 int len=0;
 in.mark(1);
in.read() //第一次讀取
in.reset();//又可以重新讀取

in.read()//第二次讀取跟第一次讀取結果一樣。因爲只讀了一個,沒有超過mark設置的整數。所以mark有效

}


public static void main(String[] args) throws IOException {
 TestInputStream test = new TestInputStream();
 String fileName = "F:/Google.txt";
 InputStream in1 = new FileInputStream(new File(fileName));
 if(!in1.markSupported()) {
 in1 = new BufferedInputStream(in1);
 }
 test.read(in1);
 byte[] buf = new byte[100];
 while(in1.read(buf, 0, buf.length)!=-1) {
 System.out.println(buf);
 }

 System.out.println("Success!");
 }
}

 

 總結:

 mark

        public void mark(int readlimit)

        mark 的常規協定是:如果方法 markSupported 返回 true,那麼輸入流總是在調用 mark 之後記錄所有讀取的字節,並時刻準備在調用方法 reset 時(無論何時),再次提供這些相同的字節。但是,如果在調用 reset 之前可以從流中讀取多於 readlimit 的字節,則不需要該流記錄任何數據。

        參數:

        readlimit - 在標記位置失效前可以讀取字節的最大限制。

4 reset

public void reset() throws IOException

        將此流重新定位到最後一次對此輸入流調用 mark 方法時的位置。

        reset 的常規協定是:

        1、如果方法 markSupported 返回 true,那麼:

        如果創建流以後未調用方法 mark,或最後調用 mark 以後從該流讀取的字節數大於最後調用 mark 時的參數,則可能拋出 IOException。

        如果未拋出這樣的 IOException,則將該流重新設置爲這種狀態:最近一次調用 mark 以後(如果未調用過 mark,則從文件開頭開始)讀取的所有字節將重新提供給 read 方法的後續調用者,後跟任何從調用 reset 時起將作爲下一輸入數據的字節。

        2、如果方法 markSupported 返回 false,那麼:

        對 reset 的調用可能拋出 IOException。

        如果未拋出 IOException,則將該流重新設置爲一種固定狀態,該狀態取決於輸入流的特定類型及其創建方式。提供給 read 方法後續調用者的字節取決於特定類型的輸入流。

        除了拋出 IOException 之外,類 InputStream 的方法 reset 不執行任何操作。

        拋出:

          IOException - 如果未標記此流或該標記失效。

發佈了30 篇原創文章 · 獲贊 36 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章