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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

NIO详解

發(fā)布時間:2025/5/22 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NIO详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

  • NIO
  • 前言
  • IO與NIO的區(qū)別
  • Buffer(緩沖區(qū))
  • Channel(通道)
  • Charset(字符集)
  • NIO遍歷文件

NIO

前言

NIO即New IO,這個庫是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但實現(xiàn)方式不同,NIO主要用到的是塊,所以NIO的效率要比IO高很多。在Java API中提供了兩套NIO,一套是針對標準輸入輸出NIO,另一套就是網(wǎng)絡編程NIO。

IO與NIO的區(qū)別

  • IO流是面向流的,屬于阻塞IO,沒有選擇器。
  • NIO流是面向塊(緩沖區(qū)),屬于非阻塞IO有選擇器。
    其中最大的區(qū)別就是一個面向流,一個面向緩沖區(qū)。
    • 面向流:IO流每次讀取一個字節(jié)或者多個,直到讀完為止。不能對流中的數(shù)據(jù)進行操作。
    • 面向緩沖區(qū):NIO流是將數(shù)據(jù)放到一個緩沖區(qū),需要時可以對緩沖區(qū)中的數(shù)據(jù)進行操作,這樣就可以更加靈活的操作數(shù)據(jù)了。(就好像IO流是一根水管,而NIO是一個運水車)

Buffer(緩沖區(qū))

Buffer是一個抽象類;
子類有:ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer
核心類(常用類):ByteBuffer和CharBuffer 其中ByteBuffer有一個子類MappedByteBuffer(MappedByteBuffer類能夠?qū)⑽募苯佑成涞絻?nèi)存中,那么這樣我們就可以像訪問內(nèi)存一樣訪問文件,非常方便)

創(chuàng)建Buffer

因為Buffer都是抽象類,無法直接實例化。創(chuàng)建緩沖區(qū)要調(diào)用XxxBuffer allocate(int capacity),XxxBuffer allocateDirect(int capacity),參數(shù)是緩沖區(qū)容量。

eg:獲取ByteBuffer
static ByteBuffer allocate(int capacity)
分配一個新的字節(jié)緩沖區(qū)(普通Buffer)
static ByteBuffer allocateDirect(int capacity)
分配新的直接字節(jié)緩沖區(qū)(直接Buffer)

二者的區(qū)別:

  • 創(chuàng)建普通Buffer成本低,讀寫的效率不高
  • 因為創(chuàng)建直接Buffer成本高,所以我們一般用在Buffer生存周期較長的時候使用
  • 只有ByteBuffer才能夠創(chuàng)建直接Buffer,其他的Buffer對象是不能夠創(chuàng)建
  • 如果創(chuàng)建了直接Buffer但是我又想要使用其他Buffer的功能,可以將ByteBuffer轉(zhuǎn)換成其他Buffer
  • Buffer參數(shù)
    • capacity(容量):緩沖區(qū)的容量,不可以為負數(shù),一旦創(chuàng)建了就不能夠改變
    • limit(界限):是緩沖區(qū)讀寫數(shù)據(jù)的終止點,limit之后的區(qū)域無法訪問
    • position(起始指針):是緩沖區(qū)讀寫數(shù)據(jù)的起始點,初始值為0。position隨著數(shù)據(jù)的加入而改變,例如讀取2個數(shù)據(jù)到Buffer中,則position = 2
    • mark(標記):該索引能夠用于下次讀取或者寫入,mark在0~position之間,設置該值就會把position移動到mark處

    Buffer方法
    • flip():讀取模式;確定緩沖區(qū)數(shù)據(jù)的起始點和終止點,為輸出數(shù)據(jù)做準備(即寫入通道), 將limit的值改為postion的值,同時將postion歸0
      • 特點: 就是為下一次數(shù)據(jù)的讀取做好準備
    • clear():寫入模式;緩沖區(qū)初始化,準備再次接收新數(shù)據(jù)到緩沖區(qū),將limit改為capacity的值,同時將postion歸0
      • 特點: 就是為下一次數(shù)據(jù)的寫入做好準備
    • get()和put():獲取元素和存放元素。使用clear()之后,無法直接使用get()獲取元素,需要使用get(int index)根據(jù)索引值來獲取相應元素
    • hasRemaining():判斷postion到limit之間是否還有元素。
    public static void main(String[] args) {CharBuffer buffer = CharBuffer.allocate(8);// Buffer已經(jīng)準備好了向Buffer中寫數(shù)據(jù) 寫模式System.out.println("capacity:" + buffer.capacity()); // 8System.out.println("limit:" + buffer.limit()); // 8System.out.println("position:" + buffer.position()); // 0 buffer.put('a');buffer.put('b');buffer.put('c');System.out.println("------------------------"); System.out.println("capacity:" + buffer.capacity()); // 8System.out.println("limit:" + buffer.limit()); // 8System.out.println("position:" + buffer.position()); // 3 System.out.println("------------------------");// 切換模式 ,limit變?yōu)閜osition的位置然后將position變?yōu)?buffer.flip();System.out.println("capacity:" + buffer.capacity()); // 8System.out.println("limit:" + buffer.limit()); // 3System.out.println("position:" + buffer.position()); // 0System.out.println("------------------------");System.out.println("------------------");buffer.clear(); // 將postion 清 0 ,將limit = capacity System.out.println("capacity:" + buffer.capacity()); // 8System.out.println("limit:" + buffer.limit()); // 8System.out.println("position:" + buffer.position()); // 0// 注意: 調(diào)用clear方法只是將讀模式改為寫模式,并不會清空緩沖區(qū)的數(shù)據(jù)}

    Channel(通道)

    Channel原理類似于傳統(tǒng)的流對象,區(qū)別在于:
    1.Channel能夠?qū)⒅付ǖ牟糠只蛘呷课募成涞絻?nèi)存中
    2.程序如果想要讀取Channel中的數(shù)據(jù),不能夠直接讀寫,必須經(jīng)過Buffer
    簡單來說:Channel通過Buffer(緩沖區(qū))進行讀寫操作。read()表示讀取通道數(shù)據(jù)到緩沖區(qū),write()表示把緩沖區(qū)數(shù)據(jù)寫入到通道。

    Channel實現(xiàn)類
    • FileChannel 和文件相關的通道
    • DatagramChannel 和UDP協(xié)議傳輸數(shù)據(jù)相關的通道
    • SocketChannel 和TCP協(xié)議相關的數(shù)據(jù)傳輸通道
    • ServerSocket 和TCP協(xié)議相關的數(shù)據(jù)傳輸通道
    • Pipe.SinkChannel、Pipe.SourceChannel //線程通信管道傳輸數(shù)據(jù)
    Channel常用方法
    • read() : 將Channel中的數(shù)據(jù)讀取到Buffer中
    • write() : 向Buffer中寫入數(shù)據(jù)
    • map(): 將channel中的數(shù)據(jù)全部或者部分映射到Buffer中(MappedByteBuffer,本質(zhì)也是一個ByteBuffer),map()方法參數(shù)(讀寫模式,映射起始位置,數(shù)據(jù)長度)。
      • inChannel.map(mode, position, size)
      • MappedByteBuffer mappBuffer = inChannel.map(MapMode.READ_ONLY, 0, srcFile.length());
    public static void main(String[] args) throws IOException {File srcFile = new File("nio-a.txt");FileInputStream fis = new FileInputStream(srcFile);FileOutputStream fos = new FileOutputStream(new File("nio-b.txt"));// 獲取Channel對象FileChannel inChannel = fis.getChannel();FileChannel outChannel = fos.getChannel();// 獲取MapByteBuffer對象MappedByteBuffer mapBuffer = inChannel.map(MapMode.READ_ONLY, 0, srcFile.length());//字符集解碼器 Charset charset = Charset.forName("GBK");outChannel.write(mapBuffer);CharsetDecoder decoder = charset.newDecoder();CharBuffer charBuffer = decoder.decode(mapBuffer);System.out.println(charBuffer);}

    通道可以異步讀寫,異步讀寫表示通道執(zhí)行讀寫操作時,也能做別的事情,解決線程阻塞。如果使用文件管道(FileChannel),建議用RandomAccessFile來創(chuàng)建管道,因為該類支持讀寫模式以及有大量處理文件的方法。

    public static void main(String[] args) throws Exception {File f = new File("nio-a.txt");RandomAccessFile raf = new RandomAccessFile(f, "rw");FileChannel channel = raf.getChannel();MappedByteBuffer mapBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());// raf.seek(f.length());channel.position(f.length());channel.write(mapBuffer);}

    Charset(字符集)

    理解為現(xiàn)實生活的編碼表對象
    當使用NIO來獲取文件內(nèi)容時,如果是文本數(shù)據(jù),那么需要進行轉(zhuǎn)碼,才能查看正確內(nèi)容,這就需要解碼器。 如果要把字符數(shù)據(jù)寫入文件,需要將CharBuffer轉(zhuǎn)碼成ByteBuffer,這就需要編碼器。

    • 包含了字節(jié)和 Unicode 字符之間轉(zhuǎn)換的 charset,還定義了用于創(chuàng)建解碼器和編碼器以及獲取與 charset 關聯(lián)的各種方法
    • CharsetDecoder(解碼器):把字節(jié)轉(zhuǎn)成字符,例如查看文本數(shù)據(jù),需要轉(zhuǎn)成字符才能查看,如果是字節(jié),就看不懂了。
    • CharsetEncoder(編碼器):把字符轉(zhuǎn)成字節(jié),才能被計算機理解。 因為字節(jié)是計算機最小的存儲單位,所以Channel的IO操作都與ByteBuffer有關
    • 解碼器和編碼器都不能直接創(chuàng)建,需要一個Charset對象來創(chuàng)建對應的解碼器和編碼器。
    Charset常用方法
    • forName():根據(jù)傳入的字符集獲得對應的字符集對象。
    • defaultCharset():獲得當前使用的默認字符集。
    • availableCharsets():獲得所有有效的字符集。

    NIO遍歷文件

    public static void main(String[] args) throws IOException {//匿名子對象實現(xiàn)FileVisitor接口FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {@Overridepublic FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {System.out.println("正在訪問" + path + "文件");if(path.endsWith("NIODemo.java")){System.out.println("恭喜您找到Java");return FileVisitResult.CONTINUE;}return FileVisitResult.CONTINUE;}@Overridepublic FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs) throws IOException {System.out.println("準備訪問" + path + "文件");return FileVisitResult.CONTINUE;}@Overridepublic FileVisitResult visitFileFailed(Path path, IOException exc) throws IOException {System.out.println("準備訪問" + path + "文件失敗");System.out.println(exc.getMessage());return FileVisitResult.CONTINUE;}};//訪問文件樹Files.walkFileTree(Paths.get("D:\\JavaSE"), visitor);}

    以上

    @Fzxey

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

    總結

    以上是生活随笔為你收集整理的NIO详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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