《疯狂Java讲义》(三十三)---- NIO

  • Buffer

Buffer没有构造函数,只能通过static XxxBuffer allocate(int capacity) 来创建一个容量为capacity的XxxBuffer.

package com.ivy.nio;

import java.nio.CharBuffer;

public class BufferDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        CharBuffer buffer = CharBuffer.allocate(8);
        System.out.println("capacity:" + buffer.capacity());
        System.out.println("limit:" + buffer.limit());
        System.out.println("position:" + buffer.position());
        
        buffer.put("a");
        buffer.put("b");
        buffer.put("c");
        System.out.println("after adding three elements -------");
        System.out.println("position:" + buffer.position());
        buffer.flip();
        System.out.println("after flip -------");
        System.out.println("position:" + buffer.position());
        System.out.println("position(0):" + buffer.get());
        System.out.println("position:" + buffer.position());
        buffer.clear();
        System.out.println("after clear -------");
        System.out.println("limit:" + buffer.limit());
        System.out.println("position:" + buffer.position());
        System.out.println("position(2):" + buffer.get(2));
        System.out.println("position:" + buffer.position());
    }

}

三个重要概念,容量,界限,位置:

  1. 容量(capacity):缓冲区的容量,最多可以存多少数据。
  2. 界限(limit):第一个不应该被读出或写入的缓冲区位置索引,也就是说,位于limit后的数据既不可读,也不可写。
  3. 位置(position):用于指明下一个可以被读出的或写入到缓冲区位置索引,当读数据时,positon的值恰好等于已经读了多少数据。

当Buffer装入数据解暑后,调用Buffer的flip方法,该方法将limit设置为position所在的位置,将position设为0,这样buffer就为输出数据做好了准备;当Buffer输出数据结束后,Buffer调用clear方法,它并不是清空数据,仅仅将position位置置为0,将limit置为capacity,这样为再次向Buffer中装入数据做好准备。

  • 使用Channel

Channel类似于传统的流对象,但与传统的流对象有两个主要区别:

  1. Channel可以直接将制定文件的部分或全部直接映射成Buffer。
  2. 程序不能直接访问Channel的数据,包括读取,写入都不行,Channel只能与Buffer进行交互。

所有的Channel都不应该通过构造器来直接创建,而是通过传统的节点InputStream,OutputStream的getChannel方法来返回对应的Channel,不同的节点流获得的Channel不一样。

Channel中最常用的3个方法是map(), read()和write(). map()方法的方法签名为:MappedByteBuffer map(FileChannel.MapMode mode, long position, long size). 第一个参数执行映射时的模式,分别有只读/读写等模式,第二第三个参数用于控制将Channel的哪些数据映射成ByteBuffer。

package com.ivy.nio;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

public class FileChannelDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        File f = new File("./src/com/ivy/nio/FileChannelDemo.java");
        try (
                FileChannel inChannel = new FileInputStream(f).getChannel();
                FileChannel outChannel = new FileOutputStream("channelOutput.txt").getChannel()) {
            MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());
            Charset charset = Charset.forName("GBK");
            outChannel.write(buffer);
            buffer.clear();
            CharsetDecoder decoder = charset.newDecoder();
            CharBuffer charBuffer = decoder.decode(buffer);
            System.out.println(charBuffer);
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

}
package com.ivy.nio;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class RandomFileChannelDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        File f= new File("channelOutput.txt");
        try (
                RandomAccessFile raf = new RandomAccessFile(f, "rw");
                FileChannel randomChannel = raf.getChannel();) {
            
            MappedByteBuffer buffer = randomChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());
            randomChannel.position(f.length());
            randomChannel.write(buffer);
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
                
    }

}
  • Charset
package com.ivy.nio;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;


public class CharsetTransformDemo {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub

        Charset cn = Charset.forName("GBK");
        CharsetEncoder cnEncoder = cn.newEncoder();
        CharsetDecoder cnDecoder = cn.newDecoder();
        CharBuffer cBuffer = CharBuffer.allocate(8);
        cBuffer.put("孙");
        cBuffer.put("悟");
        cBuffer.put("空");
        cBuffer.flip();
        ByteBuffer bBuffer = cnEncoder.encode(cBuffer);
        for (int i = 0; i < bBuffer.capacity(); i++) {
            System.out.print(bBuffer.get(i)  + " ");
        }
        System.out.println("
" + cnDecoder.decode(bBuffer));
    }

}

实际上,Charset类也提供了decode(ByteBuffer bb), encode(CharBuffer cb)和encode(String str),也就是说,获取了Charset对象后,如果仅仅需要进行简单的编码解码操作,其实无须创建CharsetEncoder & CharsetDecoder,直接调用Charst的encode和decode方法进行编码和解码就行。

  • 文件锁

在NIO中,Java提供了FileLock来支持文件锁。

原文地址:https://www.cnblogs.com/IvySue/p/6404329.html