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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Java IO流学习总结三:缓冲流-BufferedInputStream、BufferedOutputStream

發(fā)布時間:2023/11/27 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java IO流学习总结三:缓冲流-BufferedInputStream、BufferedOutputStream 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Java IO流學習總結(jié)三:緩沖流-BufferedInputStream、BufferedOutputStream

轉(zhuǎn)載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/54894451
本文出自【趙彥軍的博客】

InputStream
|__FilterInputStream|__BufferedInputStream

首先拋出一個問題,有了InputStream為什么還要有BufferedInputStream?

BufferedInputStreamBufferedOutputStream這兩個類分別是FilterInputStreamFilterOutputStream的子類,作為裝飾器子類,使用它們可以防止每次讀取/發(fā)送數(shù)據(jù)時進行實際的寫操作,代表著使用緩沖區(qū)。

我們有必要知道不帶緩沖的操作,每讀一個字節(jié)就要寫入一個字節(jié),由于涉及磁盤的IO操作相比內(nèi)存的操作要慢很多,所以不帶緩沖的流效率很低。帶緩沖的流,可以一次讀很多字節(jié),但不向磁盤中寫入,只是先放到內(nèi)存里。等湊夠了緩沖區(qū)大小的時候一次性寫入磁盤,這種方式可以減少磁盤操作次數(shù),速度就會提高很多!

同時正因為它們實現(xiàn)了緩沖功能,所以要注意在使用BufferedOutputStream寫完數(shù)據(jù)后,要調(diào)用flush()方法或close()方法,強行將緩沖區(qū)中的數(shù)據(jù)寫出。否則可能無法寫出數(shù)據(jù)。與之相似還BufferedReaderBufferedWriter兩個類。

現(xiàn)在就可以回答在本文的開頭提出的問題:

BufferedInputStreamBufferedOutputStream類就是實現(xiàn)了緩沖功能的輸入流/輸出流。使用帶緩沖的輸入輸出流,效率更高,速度更快。

總結(jié):

  • BufferedInputStream 是緩沖輸入流。它繼承于FilterInputStream

  • BufferedInputStream 的作用是為另一個輸入流添加一些功能,例如,提供“緩沖功能”以及支持mark()標記reset()重置方法

  • BufferedInputStream 本質(zhì)上是通過一個內(nèi)部緩沖區(qū)數(shù)組實現(xiàn)的。例如,在新建某輸入流對應的BufferedInputStream后,當我們通過read()讀取輸入流的數(shù)據(jù)時,BufferedInputStream會將該輸入流的數(shù)據(jù)分批的填入到緩沖區(qū)中。每當緩沖區(qū)中的數(shù)據(jù)被讀完之后,輸入流會再次填充數(shù)據(jù)緩沖區(qū);如此反復,直到我們讀完輸入流數(shù)據(jù)位置。

BufferedInputStream API簡介

源碼關鍵字段分析


private static int defaultBufferSize = 8192;//內(nèi)置緩存字節(jié)數(shù)組的大小 8KBprotected volatile byte buf[];  //內(nèi)置緩存字節(jié)數(shù)組protected int count;    //當前buf中的字節(jié)總數(shù)、注意不是底層字節(jié)輸入流的源中字節(jié)總數(shù)protected int pos;      //當前buf中下一個被讀取的字節(jié)下標protected int markpos = -1; //最后一次調(diào)用mark(int readLimit)方法記錄的buf中下一個被讀取的字節(jié)的位置protected int marklimit;    //調(diào)用mark后、在后續(xù)調(diào)用reset()方法失敗之前云尋的從in中讀取的最大數(shù)據(jù)量、用于限制被標記后buffer的最大值

構(gòu)造函數(shù)

BufferedInputStream(InputStream in) //使用默認buf大小、底層字節(jié)輸入流構(gòu)建bis BufferedInputStream(InputStream in, int size) //使用指定buf大小、底層字節(jié)輸入流構(gòu)建bis  

一般方法介紹

int available();  //返回底層流對應的源中有效可供讀取的字節(jié)數(shù)      void close();  //關閉此流、釋放與此流有關的所有資源  boolean markSupport();  //查看此流是否支持markvoid mark(int readLimit); //標記當前buf中讀取下一個字節(jié)的下標  int read();  //讀取buf中下一個字節(jié)  int read(byte[] b, int off, int len);  //讀取buf中下一個字節(jié)  void reset();   //重置最后一次調(diào)用mark標記的buf中的位子  long skip(long n);  //跳過n個字節(jié)、 不僅僅是buf中的有效字節(jié)、也包括in的源中的字節(jié) 

BufferedOutputStream API簡介

關鍵字段

protected byte[] buf;   //內(nèi)置緩存字節(jié)數(shù)組、用于存放程序要寫入out的字節(jié)  protected int count;   //內(nèi)置緩存字節(jié)數(shù)組中現(xiàn)有字節(jié)總數(shù) 

構(gòu)造函數(shù)

BufferedOutputStream(OutputStream out); //使用默認大小、底層字節(jié)輸出流構(gòu)造bos。默認緩沖大小是 8192 字節(jié)( 8KB )BufferedOutputStream(OutputStream out, int size);  //使用指定大小、底層字節(jié)輸出流構(gòu)造bos  

構(gòu)造函數(shù)源碼:

/*** Creates a new buffered output stream to write data to the* specified underlying output stream.* @param   out   the underlying output stream.*/public BufferedOutputStream(OutputStream out) {this(out, 8192);}/*** Creates a new buffered output stream to write data to the* specified underlying output stream with the specified buffer* size.** @param   out    the underlying output stream.* @param   size   the buffer size.* @exception IllegalArgumentException if size &lt;= 0.*/public BufferedOutputStream(OutputStream out, int size) {super(out);if (size <= 0) {throw new IllegalArgumentException("Buffer size <= 0");}buf = new byte[size];}

一般方法

//在這里提一句,`BufferedOutputStream`沒有自己的`close`方法,當他調(diào)用父類`FilterOutputStrem`的方法關閉時,會間接調(diào)用自己實現(xiàn)的`flush`方法將buf中殘存的字節(jié)flush到out中,再`out.flush()`到目的地中,DataOutputStream也是如此。 void  flush();  將寫入bos中的數(shù)據(jù)flush到out指定的目的地中、注意這里不是flush到out中、因為其內(nèi)部又調(diào)用了out.flush()  write(byte b);      將一個字節(jié)寫入到buf中  write(byte[] b, int off, int len);      將b的一部分寫入buf中 

那么什么時候flush()才有效呢?
答案是:當OutputStream是BufferedOutputStream時。

當寫文件需要flush()的效果時,需要
FileOutputStream fos = new FileOutputStream("c:\a.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
也就是說,需要將FileOutputStream作為BufferedOutputStream構(gòu)造函數(shù)的參數(shù)傳入,然后對BufferedOutputStream進行寫入操作,才能利用緩沖及flush()。

查看BufferedOutputStream的源代碼,發(fā)現(xiàn)所謂的buffer其實就是一個byte[]。
BufferedOutputStream的每一次write其實是將內(nèi)容寫入byte[],當buffer容量到達上限時,會觸發(fā)真正的磁盤寫入。
而另一種觸發(fā)磁盤寫入的辦法就是調(diào)用flush()了。

1.BufferedOutputStreamclose()時會自動flush
2.BufferedOutputStream在不調(diào)用close()的情況下,緩沖區(qū)不滿,又需要把緩沖區(qū)的內(nèi)容寫入到文件或通過網(wǎng)絡發(fā)送到別的機器時,才需要調(diào)用flush.

實戰(zhàn)演練1:復制文件.
操作:使用緩存流將F盤根目錄里面名字為:123.png 圖片復制成 abc.png

package com.app;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;public class A3 {public static void main(String[] args) throws IOException {String filePath = "F:/123.png" ;String filePath2 = "F:/abc.png" ;File file = new File( filePath ) ;File file2 = new File( filePath2 ) ;copyFile( file , file2 );}/*** 復制文件* @param oldFile* @param newFile*/public static void copyFile( File oldFile , File newFile){InputStream inputStream = null ;BufferedInputStream bufferedInputStream = null ;OutputStream outputStream = null ;BufferedOutputStream bufferedOutputStream = null ;try {inputStream = new FileInputStream( oldFile ) ;bufferedInputStream = new BufferedInputStream( inputStream ) ;outputStream = new FileOutputStream( newFile ) ;bufferedOutputStream = new BufferedOutputStream( outputStream ) ;byte[] b=new byte[1024];   //代表一次最多讀取1KB的內(nèi)容int length = 0 ; //代表實際讀取的字節(jié)數(shù)while( (length = bufferedInputStream.read( b ) )!= -1 ){//length 代表實際讀取的字節(jié)數(shù)bufferedOutputStream.write(b, 0, length );}//緩沖區(qū)的內(nèi)容寫入到文件bufferedOutputStream.flush();} catch (FileNotFoundException e) {e.printStackTrace();}catch (IOException e) {e.printStackTrace();}finally {if( bufferedOutputStream != null ){try {bufferedOutputStream.close();} catch (IOException e) {e.printStackTrace();}}if( bufferedInputStream != null){try {bufferedInputStream.close();} catch (IOException e) {e.printStackTrace();}}if( inputStream != null ){try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}if ( outputStream != null ) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}}
}

效果圖:

如何正確的關閉流

在上面的代碼中,我們關閉流的代碼是這樣寫的。

finally {if( bufferedOutputStream != null ){try {bufferedOutputStream.close();} catch (IOException e) {e.printStackTrace();}}if( bufferedInputStream != null){try {bufferedInputStream.close();} catch (IOException e) {e.printStackTrace();}}if( inputStream != null ){try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}if ( outputStream != null ) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}

思考:在處理流關閉完成后,我們還需要關閉節(jié)點流嗎?

讓我們帶著問題去看源碼:

  • bufferedOutputStream.close();
   /*** Closes this input stream and releases any system resources* associated with the stream.* Once the stream has been closed, further read(), available(), reset(),* or skip() invocations will throw an IOException.* Closing a previously closed stream has no effect.** @exception  IOException  if an I/O error occurs.*/public void close() throws IOException {byte[] buffer;while ( (buffer = buf) != null) {if (bufUpdater.compareAndSet(this, buffer, null)) {InputStream input = in;in = null;if (input != null)input.close();return;}// Else retry in case a new buf was CASed in fill()}}

close()方法的作用
1、關閉輸入流,并且釋放系統(tǒng)資源
2、BufferedInputStream裝飾一個 InputStream 使之具有緩沖功能,is要關閉只需要調(diào)用最終被裝飾出的對象的 close()方法即可,因為它最終會調(diào)用真正數(shù)據(jù)源對象的 close()方法。因此,可以只調(diào)用外層流的close方法關閉其裝飾的內(nèi)層流。

那么如果我們想逐個關閉流,我們該怎么做?

答案是:先關閉外層流,再關閉內(nèi)層流。一般情況下是:先打開的后關閉,后打開的先關閉;另一種情況:看依賴關系,如果流a依賴流b,應該先關閉流a,再關閉流b。例如處理流a依賴節(jié)點流b,應該先關閉處理流a,再關閉節(jié)點流b

看懂了怎么正確的關閉流之后,那么我們就可以優(yōu)化上面的代碼了,只關閉外層的處理流。

finally {if( bufferedOutputStream != null ){try {bufferedOutputStream.close();} catch (IOException e) {e.printStackTrace();}}if( bufferedInputStream != null){try {bufferedInputStream.close();} catch (IOException e) {e.printStackTrace();}}}

個人微信號:zhaoyanjun125 , 歡迎關注

轉(zhuǎn)載于:https://www.cnblogs.com/zhaoyanjun/p/6376937.html

總結(jié)

以上是生活随笔為你收集整理的Java IO流学习总结三:缓冲流-BufferedInputStream、BufferedOutputStream的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。