一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java BufferedOutputStream類的常用方法講解

Java BufferedOutputStream類的常用方法講解

2022-02-16 12:08scbiaosdo Java教程

這篇文章主要介紹了Java BufferedOutputStream類的常用方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

 

BufferedOutputStream類的常用方法

BufferedOutputStream字節緩沖輸出流

 

構造方式

第一種開發中

public BufferedOutputStream(OutputStream out)

采用的默認的緩沖區大小(足夠大了) ,來構造一個字節緩沖輸出流對象

public BufferedOutputStream(OutputStream out,int size)

指定size緩沖區大小構造緩沖輸出流對象

IllegalArgumentException - 如果 size <= 0

 

常用方法

public void write(int b)throws IOException

一次寫一個字節

  • b - 要寫入的字節。
public void write(byte[] b,int off,int len) throws IOException

一次寫一個字節數組的一部分

  • b - 數據。
  • off - 數據的起始偏移量。
  • len - 要寫入的字節數。
public void flush() throws IOException

刷新此緩沖的輸出流。這迫使所有緩沖的輸出字節被寫出到底層輸出流中。

public void close() throws IOException

關閉此輸出流并釋放與此流有關的所有系統資源。

FilterOutputStream 的 close 方法先調用其 flush 方法,然后調用其基礎輸出流的 close 方法。

 

程序示例

public static void main(String[] args) throws Exception {    
    //符合Java一種設計模式:裝飾者設計模式(過濾器:Filter)
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt")) ;        
    //寫數據
    bos.write("hello".getBytes());
    //釋放資源
    bos.close();
}

 

BufferedOutputStream深入分析

FileOutputStream和BufferedOutputStream都提供了一系列的將數據寫入文件的方式,并且我們都知道BufferedOutputStream要比直接使用FileOutputStream寫入速度要快,本文通過案例實際演示一下兩者的區別。

 

代碼準備

public class BufferFile {
    public static void main(String[] args) {
        //每次向文件中寫入一個8字節的數組
        byte[] bytes = "1234567
".getBytes();
        //每隔100毫秒通過buffer的方式向文件中寫入數據
        new Thread(() -> {
            System.out.println("buffer_while start...");
            File file = new File("/var/file_test_data/out_buffer_while.txt");
            FileOutputStream fileOutputStream;
            try {
                fileOutputStream = new FileOutputStream(file);
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                while (true) {
                    Thread.sleep(100);
                    bufferedOutputStream.write(bytes);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
        //通過buffer的方式向文件中寫入1千萬次
        new Thread(() -> {
            System.out.println("buffer_for start...");
            File file = new File("/var/file_test_data/out_buffer_for.txt");
            FileOutputStream fileOutputStream;
            try {
                fileOutputStream = new FileOutputStream(file);
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                for (int i = 0; i < 10000000; i++) {
                    bufferedOutputStream.write(bytes);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(new Date() + ": buffer_for end...");
        }).start();
        //通過file的方式向文件中寫入1千萬次
        new Thread(() -> {
            System.out.println("file_for start...");
            File file = new File("/var/file_test_data/out_file_for.txt");
            FileOutputStream fileOutputStream;
            try {
                fileOutputStream = new FileOutputStream(file);
                for (int i = 0; i < 10000000; i++) {
                    fileOutputStream.write(bytes);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(new Date() + ": file_for end...");
        }).start();
    }
}

開始運行

Java BufferedOutputStream類的常用方法講解

強行停止后的運行結果

Java BufferedOutputStream類的常用方法講解

1、file和buffe寫入速度比較

兩者分別寫入1千萬次,時間上buffer比file快8秒,如果當寫入次數指數級增加時,buffer的優勢將更加明顯。

2、數據寫入完整性問題

buffer雖然要比file快,但是從最終數據上可以看出,buffer會丟數據

  • 當第一個線程寫入時數據還未滿8kb時,強制停止java進程,最終out_buffer_while.txt沒有數據。
  • 第二個線程,雖然最終代碼執行完畢,但是比較file方式,out_buffer_for.txt文件看起來也丟了一部分數據。

 

原因分析

當使用buffer讀寫文件時,數據并沒有直接被寫入磁盤,而是被緩存到一個字節數據中,這個字節數組的大小是8kb,默認情況下只有當8kb被填充滿了以后,數據才會被一次性寫入磁盤,這樣一來就大大減少了系統調用的次數(file是每一次write都會產生系統調用),當然也正是因為buffer中的每一次write只是寫入到內存中(JVM自身內存中),所以當數據未寫入磁盤前,如果JVM進程掛了,那么就會造成數據丟失。

 

手動刷盤

為了解決數據丟失的問題,buf中提供了flush()方法,用戶可以自行決定合適將數據刷寫到磁盤中

  • 如果你的flush()調用的非常頻繁,那就會退化為普通的file模式了。
  • 如果你的flush()調用的又不太頻繁,那么丟數據的可能性就比較高。
  • 無論如何業務邏輯中數據寫完時,一定要調用一次flush(),確保緩沖區的數據刷到磁盤上。

將無限循環寫入的代碼注釋掉,在buf寫1千萬完成后,加上bufferedOutputStream.flush();

public class BufferFile {
    public static void main(String[] args) {
        //每次向文件中寫入一個8字節的數組
        byte[] bytes = "1234567
".getBytes();
        //每隔100毫秒通過buffer的方式向文件中寫入數據
        /*new Thread(() -> {
            System.out.println("buffer_while start...");
            File file = new File("/var/file_test_data/out_buffer_while.txt");
            FileOutputStream fileOutputStream;
            try {
                fileOutputStream = new FileOutputStream(file);
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                while (true) {
                    Thread.sleep(100);
                    bufferedOutputStream.write(bytes);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();*/
        //通過buffer的方式向文件中寫入1千萬次
        new Thread(() -> {
            System.out.println("buffer_for start...");
            File file = new File("/var/file_test_data/out_buffer_for.txt");
            FileOutputStream fileOutputStream;
            try {
                fileOutputStream = new FileOutputStream(file);
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                for (int i = 0; i < 10000000; i++) {
                    bufferedOutputStream.write(bytes);
                }
                bufferedOutputStream.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(new Date() + ": buffer_for end...");
        }).start();
        //通過file的方式向文件中寫入1千萬次
        new Thread(() -> {
            System.out.println("file_for start...");
            File file = new File("/var/file_test_data/out_file_for.txt");
            FileOutputStream fileOutputStream;
            try {
                fileOutputStream = new FileOutputStream(file);
                for (int i = 0; i < 10000000; i++) {
                    fileOutputStream.write(bytes);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(new Date() + ": file_for end...");
        }).start();
    }
}

這次再看數據寫入完整了

Java BufferedOutputStream類的常用方法講解

 

buffer源碼分析

類的機構圖

Java BufferedOutputStream類的常用方法講解

首先當創建一個BufferedOutputStream對象時,構造方法就初始化了緩沖的字節數組大小為8kb

	protected byte buf[];
    public BufferedOutputStream(OutputStream out) {
        this(out, 8192);
    }
    public BufferedOutputStream(OutputStream out, int size) {
        super(out);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        buf = new byte[size];
    }

當調用buffer.write(b)時,調用的是父類FilterOutputStream的方法

    public void write(byte b[]) throws IOException {
    	//寫入的字節數組b,從0開始,一共要寫入的長度
        write(b, 0, b.length);
    }
    	
    public void write(byte b[], int off, int len) throws IOException {
        if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
            throw new IndexOutOfBoundsException();
		//遍歷數組,一個字節一個字節的把數據寫入數組中
        for (int i = 0 ; i < len ; i++) {
            write(b[off + i]);
        }
    }
    
    public synchronized void write(int b) throws IOException {
    	//判斷字節長度是否超過buf.length,buf在初始化已經指定大小為8192,即8kb
    	//如果超過則調用flushBuffer
        if (count >= buf.length) {
            flushBuffer();
        }
        把每一個字節寫入緩沖的buf數組中,并且統計值count++
        buf[count++] = (byte)b;
    }
    private void flushBuffer() throws IOException {
        if (count > 0) {
        	//真正的調用OutputStream,寫入數據到磁盤中
        	//寫入buf緩沖字節數組數據,從0下標開始,一直寫到count,即有多少寫多少。
            out.write(buf, 0, count);
            count = 0;
        }
    }

 

關于buf緩沖數據大小設置

buffer提供了可以自定義緩沖大小的構造方法

    public BufferedOutputStream(OutputStream out, int size) {
        super(out);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        buf = new byte[size];
    }

如果緩沖大小設置的比較大。

  • 好處:進一步減少調用系統內核寫數據的方法,提高寫入速度,kafka的批寫入默認就是16kb寫一次。
  • 壞處:1、丟失的數據可能會更多,2、要注意堆內存的消耗。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/scbiaosdo/article/details/80422490

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久久久久久尹人综合网亚洲 | 欧美日韩国产一区二区三区不卡 | 欠操h | 日韩欧美综合在线二区三区 | 亚洲AV久久久久久久无码 | 亚洲欧美专区精品久久 | 国产高清自拍 | 农夫成人网 | 91九色在线视频 | 人人澡 人人澡碰人人看软件 | 国产欧美日韩精品一区二区三区 | 日韩一区二区三区不卡视频 | 肉宠文很肉到处做1v1 | 欧美日韩一级视频 | 亚洲 欧美 日本 国产 高清 | 97久久久亚洲综合久久88 | 欧美乱强| 国产大神91一区二区三区 | bbox撕裂bass孕妇 | 亚洲国产无线码在线观看 | 欧美综合精品一区二区三区 | 日韩精品免费看 | 日本人作爰啪啪全过程 | 久久精品黄AA片一区二区三区 | 高h孕交 | 精品小视频在线观看 | 草草影院在线 | 日日网| 久久夜色噜噜噜亚洲AV0000 | 国产一区二区精品久久91 | 日日碰碰 | 成年人免费在线看 | 久久久精品日本一区二区三区 | 日本高免费观看在线播放 | 亚州在线视频 | 日本免费观看95视频网站 | 精品免费国产 | 色婷在线| a亚洲视频 | 久久亚洲精品成人 | 娇小XXXXX第一次出血 |