日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

InputStream中通过mark和reset方法重复利用缓存

發布時間:2023/11/29 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 InputStream中通过mark和reset方法重复利用缓存 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

通過緩存InputStream可重復利用一個InputStream,但是要緩存一整個InputStream內存壓力可能是比較大的。如果第一次讀取InputStream是用來判斷文件流類型,文件編碼等用的,往往不需要所有的InputStream的數據,或許只需要前n個字節,這樣一來,緩存一整個InputStream實際上也是一種浪費。?

其實InputStream本身提供了三個接口:?
第一個,InputStream是否支持mark,默認不支持。?
public boolean markSupported() { return false; }

第二個,mark接口。該接口在InputStream中默認實現不做任何事情。?

  public?synchronized?void?mark(int?readlimit)?{} ?


第三個,reset接口。該接口在InputStream中實現,調用就會拋異常。?
public synchronized void reset() throws IOException { throw new IOException("mark/reset not supported"); }

從三個接口定義中可以看出,首先InputStream默認是不支持mark的,子類需要支持mark必須重寫這三個方法。?

第一個接口很簡單,就是標明該InputStream是否支持mark。?

調用mark方法會記下當前調用mark方法的時刻,InputStream被讀到的位置。?
調用reset方法就會回到該位置。?
舉個簡單的例子:?
String content = "BoyceZhang!"; InputStream inputStream = new ByteArrayInputStream(content.getBytes()); // 判斷該輸入流是否支持mark操作 if (!inputStream.markSupported()) { System.out.println("mark/reset not supported!"); } int ch; boolean marked = false; while ((ch = inputStream.read()) != -1) { //讀取一個字符輸出一個字符 System.out.print((char)ch); //讀到 'e'的時候標記一下 if (((char)ch == 'e')& !marked) { inputStream.mark(content.length()); //先不要理會mark的參數 marked = true; } //讀到'!'的時候重新回到標記位置開始讀 if ((char)ch == '!' && marked) { inputStream.reset(); marked = false; } } //程序最終輸出:BoyceZhang!Zhang!

看了這個例子之后對mark和reset接口有了很直觀的認識。?

mark接口的參數readlimit作用?
我們知道InputStream是不支持mark的。要想支持mark子類必須重寫這三個方法,我想說的是不同的實現子類,mark的參數readlimit作用不盡相同。?
常用的FileInputStream不支持mark。?
1. 對于BufferedInputStream,readlimit表示:InputStream調用mark方法的時刻起,在讀取readlimit個字節之前,標記的該位置是有效的。如果讀取的字節數大于readlimit,可能標記的位置會失效。?

在BufferedInputStream的read方法源碼中有這么一段:?
} else if (buffer.length >= marklimit) { markpos = -1; /* buffer got too big, invalidate mark */ pos = 0; /* drop buffer contents */ } else { /* grow buffer */

為什么是可能會失效呢??

因為BufferedInputStream讀取不是一個字節一個字節讀取的,是一個字節數組一個字節數組讀取的。?
例如,readlimit=35,第一次比較的時候buffer.length=0(沒開始讀)<readlimit?
然后buffer數組一次讀取48個字節。這時的read方法只會簡單的挨個返回buffer數組中的字節,不會做這次比較。直到讀到buffer數組最后一個字節(第48個)后,才重新再次比較。這時如果我們讀到buffer中第47個字節就reset。mark仍然是有效的。雖然47>35。?

2. 對于InputStream的另外一個實現類:ByteArrayInputStream,我們發現readlimit參數根本就沒有用,調用mark方法的時候寫多少都無所謂。?
public void mark(int readAheadLimit) { mark = pos; } public synchronized void reset() { pos = mark; }

因為對于ByteArrayInputStream來說,都是通過字節數組創建的,內部本身就保存了整個字節數組,mark只是標記一下數組下標位置,根本不用擔心mark會創建太大的buffer字節數組緩存。?


3. 其他的InputStream子類沒有去總結。原理都是一樣的。?

所以由于mark和reset方法配合可以記錄并回到我們標記的流的位置重新讀流,很大一部分就可以解決我們的某些重復讀的需要。?
這種方式的優點很明顯:不用緩存整個InputStream數據。對于ByteArrayInputStream甚至沒有任何的內存開銷。?
當然這種方式也有缺點:就是需要通過干擾InputStream的讀取細節,也相對比較復雜。

轉載于:https://www.cnblogs.com/fswhq/p/InputStream.html

總結

以上是生活随笔為你收集整理的InputStream中通过mark和reset方法重复利用缓存的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。