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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 缓冲流简介及简单用法

發布時間:2025/3/20 java 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 缓冲流简介及简单用法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在java編程中, 我們有時會聽到緩沖流和原始流等字眼.


其實在之前的博文中, 提到過流可以分為原始流和處理流.

http://blog.csdn.net/nvd11/article/details/30126233

也就是說處理流是包裹在原始流對原始流的數據進行進一步的處理, 這時的流就有兩層了.


而緩沖流就是處理流的一種.


一, 緩沖流的定義

緩沖流是處理流的一種, 它依賴于原始的輸入輸出流, 它令輸入輸出流具有1個緩沖區, 顯著減少與外部設備的IO次數, 而且提供一些額外的方法.


可見, 緩沖流最大的特點就是具有1個緩沖區! 而我們使用緩沖流無非兩個目的:

1. 減少IO次數(提升performance)

2. 使用一些緩沖流的額外的方法.



二, 不使用緩沖流的例子

下面例子, 將1個大小為32MB的音樂文件復制到另1個地方. (/home/gateman/Music/Nickelback - Rockstar.flac 復制到 /home/gateman/tmp/Rockstar.flac

而且只是用原始的 FileInputStream 和 FileOutputStream, 1個1個字節的讀取寫入.

package Stream_kng.BufferStream_kng;import java.io.*;public class Stream2{public static void f(){FileInputStream fi = null;try{fi = new FileInputStream("/home/gateman/Music/Nickelback - Rockstar.flac");}catch(FileNotFoundException e){System.out.println("File not found!");}FileOutputStream fo = null;try{fo = new FileOutputStream("/home/gateman/tmp/Rockstar.flac");}catch(Exception e){System.out.println("error in file output stream's creation");e.printStackTrace();}int byt;try{byt = fi.read();while(-1 != byt){fo.write(byt);byt = fi.read();}}catch(IOException e){e.printStackTrace();}try{fo.flush();}catch(IOException e){System.out.println("Exception in flush()");}finally{if (null != fo){try{fo.close();}catch(IOException e){System.out.println("Exception in fo.close()");}}if (null != fi){try{fi.close();}catch(IOException e){System.out.println("Exception in fi.close()");}}}System.out.println("copy done!");} }


我們看看編譯后的執行效果:

gateman@TPEOS classes $ ls /home/gateman/tmp/Rockstar.flac ls: cannot access /home/gateman/tmp/Rockstar.flac: No such file or directory gateman@TPEOS classes $ time java Enter_1 copy done!real 0m57.385s user 0m9.640s sys 0m47.528s gateman@TPEOS classes $ ls -lh /home/gateman/tmp/Rockstar.flac -rw-rw-r-- 1 gateman gateman 32M Jul 1 22:43 /home/gateman/tmp/Rockstar.flac

可見復制區區1個32m的文件都用了將近1分鐘,? 不可以接受啊.


原因就是輸入流fi 和 輸出流都是1個1個字節的讀寫, 也就是說這個程序對硬盤讀了 30000多次, 寫了30000多次.

而硬盤IO是整個計算機最慢的動作, 所以我們需要減少外部設備的IO.


方法很簡單, 就是增加每一次IO的數據量(緩沖), 自然就是減少了IO次數.


三, 使用緩沖流的例子

上面的代碼只有兩個流.

輸入流fi 和 輸出流.

下面修改一下, 增加兩個緩沖流, 分別包裹著原始的輸入輸出流.

package Stream_kng.BufferStream_kng;import java.io.*;public class BufferStream1{public static void f(){FileInputStream fi = null;try{fi = new FileInputStream("/home/gateman/Music/Nickelback - Rockstar.flac");}catch(FileNotFoundException e){System.out.println("File not found!");}FileOutputStream fo = null;try{fo = new FileOutputStream("/home/gateman/tmp/Rockstar.flac");}catch(Exception e){System.out.println("error in file output stream's creation");e.printStackTrace();}//bufferStreamBufferedInputStream bis = new BufferedInputStream(fi,512);BufferedOutputStream bos = new BufferedOutputStream(fo,512);int byt;try{byt = bis.read();while(-1 != byt){bos.write(byt);byt = bis.read();}}catch(IOException e){e.printStackTrace();}try{bos.flush();}catch(IOException e){System.out.println("Exception in flush()");}finally{if (null != bos){try{bos.close();}catch(IOException e){System.out.println("Exception in bos.close()");}}if (null != bis){try{bis.close();}catch(IOException e){System.out.println("Exception in bis.close()");}}}System.out.println("copy done!!");} }

分析上面代碼,?

BufferedInputStream bis = new BufferedInputStream(fi,512);BufferedOutputStream bos = new BufferedOutputStream(fo,512);

這兩句就建立了兩個緩沖流對象, 分別包裹了 原始的輸入流fi 和 原始的輸出流fo. 并指定緩沖區的大小未512kb


后面就只調用緩沖流的read()和write方法.

代碼看起來還是1個1個字節地讀寫的, 跟第二節例子很類似.


但是執行效果大大不同:

gateman@TPEOS classes $ ls -lh /home/gateman/tmp/Rockstar.flac ls: cannot access /home/gateman/tmp/Rockstar.flac: No such file or directory gateman@TPEOS classes $ time java Enter_1 copy done!!real 0m1.766s user 0m1.612s sys 0m0.168s gateman@TPEOS classes $ ls -lh /home/gateman/tmp/Rockstar.flac -rw-rw-r-- 1 gateman gateman 32M Jul 1 23:19 /home/gateman/tmp/Rockstar.flac
可見這次執行了1.766秒, 相比之前的57多秒簡直不可以同日而語.


原因就是緩沖輸入流會預讀到512k(緩沖區大小)字節才發給程序, 緩沖輸出流寫滿緩沖區(512k)才寫入外部設備.


如下圖:





四, 緩沖流輸入流 BufferedInputStream流的常用方法介紹

上面程序使用了兩個緩沖流:

BufferedInputStream 和 BufferedOutputStream.

分別對應輸入和輸出.


其實它們的機制類似.

這里只介紹緩沖輸入流的常用方法:


4.1 new BufferedInputStream(InputStream is, int bufferSize)

這個是緩沖輸入流最常用的構造方法.

它有兩個參數, 第一個就是要包裹的輸入流,? 其中InputStream是1個抽象類, 實際上我們傳送的是其子類(例如上面例子的FileInputStream)的對象, 這里用到多態的知識.

第二個參數也很重要, 就是制定緩沖流緩沖區的初始大小. 單位是kb 上面的例子我們指定為512kb.


注意構造方法并不需要強制捕捉異常.


4.2 int read() throws IOException

讀取一個字節放入緩沖區, 用法與InputStream的read()基本一樣的.


4.3 int read(byte[] bytArr) throws IOException

讀取若干個字節放入字節數組bytArr, 返回實際讀取的字節個數, 用法與InputStream的同名同參方法基本一樣.


4.4 void mark(int readlimit) 和 void reset() throws IOException

這個方法就是緩沖輸入流額外提供的方法.


它的作用就是在當前位置作1個標記,? 它允許調用另1個方法reset() 令到流重新定位到這個標記上.

有點類似于oracle 的transation 的savepoint 和 rollback


它有什么意義?

它可以令我們在流中定1個標記, 然后讀取標記后的若干數據作判斷or處理, 如果符合某一條件可以返回到標記位置重新讀取...


它的參數 int readlimit?

意思是, 調用reset()前允許讀取的字節個個數,? 更通俗地說, 一旦你標記后讀取超過了readlimit個字節, 那么就不可再調用reset()了, 會拋異常.


而且, 這些操作都是基于緩沖區內處理的, 所以標記后讀取的字節數也不能大于緩沖區大小再調用reset(), 所以 readlimit設置大于緩沖區是沒有意義的.


4.5 void close() throws IOException

上面的例子有4個流, 兩個原始流, 兩個緩沖流, 但是到了代碼的最后只關閉了兩個緩沖流.


實際上, java中關閉1個處理流, 會自動調用處理流包裹的原始流的close()方法, 也就是說回嵌套地關閉流, 所以只需要關閉緩沖流, 不需關閉原始流, 否則拋異常!



五, 不使用緩沖流的緩沖機制.

實際上很多人都明白, 基本的原始流InputStream 有1個方法

int read(byte[]) 一次性地讀取多個字節.

這個byte[] 字節數組實際上也是1個緩沖區.


下面例子:

package Stream_kng.BufferStream_kng;import java.io.*;public class Stream3{public static void f(){FileInputStream fi = null;try{fi = new FileInputStream("/home/gateman/Music/Nickelback - Rockstar.flac");}catch(FileNotFoundException e){System.out.println("File not found!");}FileOutputStream fo = null;try{fo = new FileOutputStream("/home/gateman/tmp/Rockstar.flac");}catch(Exception e){System.out.println("error in file output stream's creation");e.printStackTrace();}byte[] byteArr = new byte[512]; //use a buffer instead of a byteint len;try{len = fi.read(byteArr);while(-1 != len){fo.write(byteArr,0,len);len = fi.read(byteArr);}}catch(IOException e){e.printStackTrace();}try{fo.flush();}catch(IOException e){System.out.println("Exception in flush()");}finally{if (null != fo){try{fo.close();}catch(IOException e){System.out.println("Exception in fo.close()");}}if (null != fi){try{fi.close();}catch(IOException e){System.out.println("Exception in fi.close()");}}}System.out.println("copy done!!");} }

上面例子沒有使用緩沖流, 只有兩個基本的字節輸入輸入流.

但是每一次讀寫都是利用到緩沖字節數組 bytArr.


實際上的效果也起到了緩沖作用, 緩沖的大小就是字節數組的大小(例子中是512k)

執行效果

ls: cannot access /home/gateman/tmp/Rockstar.flac: No such file or directory gateman@TPEOS classes $ time java Enter_1 copy done!!real 0m0.246s user 0m0.120s sys 0m0.136s gateman@TPEOS classes $ ls -lh /home/gateman/tmp/Rockstar.flac -rw-rw-r-- 1 gateman gateman 32M Jul 1 23:48 /home/gateman/tmp/Rockstar.flac

實際效果更快了, 只需0.246s

貌似比使用緩沖流效果更好啊.


那么為何還需要緩沖流呢?

答案就是 緩沖流有預讀機制,比起使用緩沖數組的緩沖效果更加明顯, 如果處理一些大數據文件, 或者網絡傳輸, 使用緩沖流的效果會更加好!


六, 總結

讀到這里, 大家應該知道緩沖流的意義就是緩沖數據.


實際上很多常用的程序都有用到緩沖流的技術, 例如迅雷下載, 有緩沖區設置, 下載一定量的數據到內存, 然后一次過寫入到硬盤, 就大大減少了寫硬盤的次數.

還有在線視頻的緩沖, 都是差不多的機制.




總結

以上是生活随笔為你收集整理的Java 缓冲流简介及简单用法的全部內容,希望文章能夠幫你解決所遇到的問題。

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