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

      歡迎訪問 生活随笔!

      生活随笔

      當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

      java

      小师妹学JavaIO之:Buffer和Buff

      發(fā)布時間:2024/2/28 java 40 豆豆
      生活随笔 收集整理的這篇文章主要介紹了 小师妹学JavaIO之:Buffer和Buff 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

      文章目錄

      • 簡介
      • Buffer是什么
      • Buffer進階
      • 創(chuàng)建Buffer
      • Direct VS non-Direct
      • Buffer的日常操作
        • 向Buffer寫數(shù)據(jù)
        • 從Buffer讀數(shù)據(jù)
        • rewind Buffer
        • Compact Buffer
        • duplicate Buffer
      • 總結(jié)

      簡介

      小師妹在學(xué)習(xí)NIO的路上越走越遠,唯一能夠幫到她的就是在她需要的時候給她以全力的支持。什么都不說了,今天介紹的是NIO的基礎(chǔ)Buffer。老鐵給我上個Buff。

      Buffer是什么

      小師妹:F師兄,這個Buffer是我們縱橫王者峽谷中那句:老鐵給我加個Buff的意思嗎?

      當(dāng)然不是了,此Buffer非彼Buff,Buffer是NIO的基礎(chǔ),沒有Buffer就沒有NIO,沒有Buffer就沒有今天的java。

      因為NIO是按Block來讀取數(shù)據(jù)的,這個一個Block就可以看做是一個Buffer。我們在Buffer中存儲要讀取的數(shù)據(jù)和要寫入的數(shù)據(jù),通過Buffer來提高讀取和寫入的效率。

      更多精彩內(nèi)容且看:

      • 區(qū)塊鏈從入門到放棄系列教程-涵蓋密碼學(xué),超級賬本,以太坊,Libra,比特幣等持續(xù)更新
      • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續(xù)更新
      • Spring 5.X系列教程:滿足你對Spring5的一切想象-持續(xù)更新
      • java程序員從小工到專家成神之路(2020版)-持續(xù)更新中,附詳細文章教程

      更多內(nèi)容請訪問www.flydean.com

      還記得java對象的底層存儲單位是什么嗎?

      小師妹:這個我知道,java對象的底層存儲單位是字節(jié)Byte。

      對,我們看下Buffer的繼承圖:

      Buffer是一個接口,它下面有諸多實現(xiàn),包括最基本的ByteBuffer和其他的基本類型封裝的其他Buffer。

      小師妹:F師兄,有ByteBuffer不就夠了嗎?還要其他的類型Buffer做什么?

      小師妹,山珍再好,也有吃膩的時候,偶爾也要換個蘿卜白菜啥的,你以為乾隆下江南都干了些啥?

      ByteBuffer雖然好用,但是它畢竟是最小的單位,在它之上我們還有Char,int,Double,Short等等基礎(chǔ)類型,為了簡單起見,我們也給他們都搞一套Buffer。

      Buffer進階

      小師妹:F師兄,既然Buffer是這些基礎(chǔ)類型的集合,為什么不直接用結(jié)合來表示呢?給他們封裝成一個對象,好像有點多余。

      我們既然在面向?qū)ο蟮氖澜?#xff0c;從表面來看自然是使用Object比較合乎情理,從底層的本質(zhì)上看,這些封裝的Buffer包含了一些額外的元數(shù)據(jù)信息,并且還提供了一些意想不到的功能。

      上圖列出了Buffer中的幾個關(guān)鍵的概念,分別是Capacity,Limit,Position和Mark。Buffer底層的本質(zhì)是數(shù)組,我們以ByteBuffer為例,它的底層是:

      final byte[] hb;
      • Capacity表示的是該Buffer能夠承載元素的最大數(shù)目,這個是在Buffer創(chuàng)建初期就設(shè)置的,不可以被改變。
      • Limit表示的Buffer中可以被訪問的元素個數(shù),也就是說Buffer中存活的元素個數(shù)。
      • Position表示的是下一個可以被訪問元素的index,可以通過put和get方法進行自動更新。
      • Mark表示的是歷史index,當(dāng)我們調(diào)用mark方法的時候,會把設(shè)置Mark為當(dāng)前的position,通過調(diào)用reset方法把Mark的值恢復(fù)到position中。

      創(chuàng)建Buffer

      小師妹:F師兄呀,這么多Buffer創(chuàng)建起來是不是很麻煩?有沒有什么快捷的使用辦法?

      一般來說創(chuàng)建Buffer有兩種方法,一種叫做allocate,一種叫做wrap。

      public void createBuffer(){IntBuffer intBuffer= IntBuffer.allocate(10);log.info("{}",intBuffer);log.info("{}",intBuffer.hasArray());int[] intArray=new int[10];IntBuffer intBuffer2= IntBuffer.wrap(intArray);log.info("{}",intBuffer2);IntBuffer intBuffer3= IntBuffer.wrap(intArray,2,5);log.info("{}",intBuffer3);intBuffer3.clear();log.info("{}",intBuffer3);log.info("{}",intBuffer3.hasArray());}

      allocate可以為Buffer分配一個空間,wrap同樣為Buffer分配一個空間,不同的是這個空間背后的數(shù)組是自定義的,wrap還支持三個參數(shù)的方法,后面兩個參數(shù)分別是offset和length。

      INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10] INFO com.flydean.BufferUsage - true INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10] INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=2 lim=7 cap=10] INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10] INFO com.flydean.BufferUsage - true

      hasArray用來判斷該Buffer的底層是不是數(shù)組實現(xiàn)的,可以看到,不管是wrap還是allocate,其底層都是數(shù)組。

      需要注意的一點,最后,我們調(diào)用了clear方法,clear方法調(diào)用之后,我們發(fā)現(xiàn)Buffer的position和limit都被重置了。這說明wrap的三個參數(shù)方法設(shè)定的只是初始值,可以被重置。

      Direct VS non-Direct

      小師妹:F師兄,你說了兩種創(chuàng)建Buffer的方法,但是兩種Buffer的后臺都是數(shù)組,難道還有非數(shù)組的Buffer嗎?

      自然是有的,但是只有ByteBuffer有。ByteBuffer有一個allocateDirect方法,可以分配Direct Buffer。

      小師妹:Direct和非Direct有什么區(qū)別呢?

      Direct Buffer就是說,不需要在用戶空間再復(fù)制拷貝一份數(shù)據(jù),直接在虛擬地址映射空間中進行操作。這叫Direct。這樣做的好處就是快。缺點就是在分配和銷毀的時候會占用更多的資源,并且因為Direct Buffer不在用戶空間之內(nèi),所以也不受垃圾回收機制的管轄。

      所以通常來說只有在數(shù)據(jù)量比較大,生命周期比較長的數(shù)據(jù)來使用Direct Buffer。

      看下代碼:

      public void createByteBuffer() throws IOException {ByteBuffer byteBuffer= ByteBuffer.allocateDirect(10);log.info("{}",byteBuffer);log.info("{}",byteBuffer.hasArray());log.info("{}",byteBuffer.isDirect());try (RandomAccessFile aFile = new RandomAccessFile("src/main/resources/www.flydean.com", "r");FileChannel inChannel = aFile.getChannel()) {MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());log.info("{}",buffer);log.info("{}",buffer.hasArray());log.info("{}",buffer.isDirect());}}

      除了allocateDirect,使用FileChannel的map方法也可以得到一個Direct的MappedByteBuffer。

      上面的例子輸出結(jié)果:

      INFO com.flydean.BufferUsage - java.nio.DirectByteBuffer[pos=0 lim=10 cap=10] INFO com.flydean.BufferUsage - false INFO com.flydean.BufferUsage - true INFO com.flydean.BufferUsage - java.nio.DirectByteBufferR[pos=0 lim=0 cap=0] INFO com.flydean.BufferUsage - false INFO com.flydean.BufferUsage - true

      Buffer的日常操作

      小師妹:F師兄,看起來Buffer確實有那么一點復(fù)雜,那么Buffer都有哪些操作呢?

      Buffer的操作有很多,下面我們一一來講解。

      向Buffer寫數(shù)據(jù)

      向Buffer寫數(shù)據(jù)可以調(diào)用Buffer的put方法:

      public void putBuffer(){IntBuffer intBuffer= IntBuffer.allocate(10);intBuffer.put(1).put(2).put(3);log.info("{}",intBuffer.array());intBuffer.put(0,4);log.info("{}",intBuffer.array());}

      因為put方法返回的還是一個IntBuffer類,所以Buffer的put方法可以像Stream那樣連寫。

      同時,我們還可以指定put在什么位置。上面的代碼輸出:

      INFO com.flydean.BufferUsage - [1, 2, 3, 0, 0, 0, 0, 0, 0, 0] INFO com.flydean.BufferUsage - [4, 2, 3, 0, 0, 0, 0, 0, 0, 0]

      從Buffer讀數(shù)據(jù)

      讀數(shù)據(jù)使用get方法,但是在get方法之前我們需要調(diào)用flip方法。

      flip方法是做什么用的呢?上面講到Buffer有個position和limit字段,position會隨著get或者put的方法自動指向后面一個元素,而limit表示的是該Buffer中有多少可用元素。

      如果我們要讀取Buffer的值則會從positon開始到limit結(jié)束:

      public void getBuffer(){IntBuffer intBuffer= IntBuffer.allocate(10);intBuffer.put(1).put(2).put(3);intBuffer.flip();while (intBuffer.hasRemaining()) {log.info("{}",intBuffer.get());}intBuffer.clear();}

      可以通過hasRemaining來判斷是否還有下一個元素。通過調(diào)用clear來清除Buffer,以供下次使用。

      rewind Buffer

      rewind和flip很類似,不同之處在于rewind不會改變limit的值,只會將position重置為0。

      public void rewindBuffer(){IntBuffer intBuffer= IntBuffer.allocate(10);intBuffer.put(1).put(2).put(3);log.info("{}",intBuffer);intBuffer.rewind();log.info("{}",intBuffer);}

      上面的結(jié)果輸出:

      INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=3 lim=10 cap=10] INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]

      Compact Buffer

      Buffer還有一個compact方法,顧名思義compact就是壓縮的意思,就是把Buffer從當(dāng)前position到limit的值賦值到position為0的位置:

      public void useCompact(){IntBuffer intBuffer= IntBuffer.allocate(10);intBuffer.put(1).put(2).put(3);intBuffer.flip();log.info("{}",intBuffer);intBuffer.get();intBuffer.compact();log.info("{}",intBuffer);log.info("{}",intBuffer.array());}

      上面代碼輸出:

      INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=3 cap=10] INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=2 lim=10 cap=10] INFO com.flydean.BufferUsage - [2, 3, 3, 0, 0, 0, 0, 0, 0, 0]

      duplicate Buffer

      最后我們講一下復(fù)制Buffer,有三種方法,duplicate,asReadOnlyBuffer,和slice。

      duplicate就是拷貝原Buffer的position,limit和mark,它和原Buffer是共享原始數(shù)據(jù)的。所以修改了duplicate之后的Buffer也會同時修改原Buffer。

      如果用asReadOnlyBuffer就不允許拷貝之后的Buffer進行修改。

      slice也是readOnly的,不過它拷貝的是從原Buffer的position到limit-position之間的部分。

      public void duplicateBuffer(){IntBuffer intBuffer= IntBuffer.allocate(10);intBuffer.put(1).put(2).put(3);log.info("{}",intBuffer);IntBuffer duplicateBuffer=intBuffer.duplicate();log.info("{}",duplicateBuffer);IntBuffer readOnlyBuffer=intBuffer.asReadOnlyBuffer();log.info("{}",readOnlyBuffer);IntBuffer sliceBuffer=intBuffer.slice();log.info("{}",sliceBuffer);}

      輸出結(jié)果:

      INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=3 lim=10 cap=10] INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=3 lim=10 cap=10] INFO com.flydean.BufferUsage - java.nio.HeapIntBufferR[pos=3 lim=10 cap=10] INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=7 cap=7]

      總結(jié)

      今天給小師妹介紹了Buffer的原理和基本操作。

      本文的例子https://github.com/ddean2009/learn-java-io-nio

      本文作者:flydean程序那些事

      本文鏈接:http://www.flydean.com/java-io-nio-buffer/

      本文來源:flydean的博客

      歡迎關(guān)注我的公眾號:程序那些事,更多精彩等著您!

      總結(jié)

      以上是生活随笔為你收集整理的小师妹学JavaIO之:Buffer和Buff的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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