java IO-3-NIO

2019-10-01  本文已影响0人  宠辱不惊的咸鱼

概述

Channel

RandomAccessFile aFile = new RandomAccessFile("resources/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();

Buffer

本质

基本用法

ByteBuffer buf = ByteBuffer.allocate(48);

public static ByteBuffer allocate(int capacity) {
    if (capacity < 0)
        throw new IllegalArgumentException();
    return new HeapByteBuffer(capacity, capacity);
}

HeapByteBuffer(int cap, int lim) {
    super(-1, 0, lim, cap, new byte[cap], 0);
}

ByteBuffer(int mark, int pos, int lim, int cap, byte[] hb, int offset) {
    // 初始书签-1;初始位置0;写限制cap
    super(mark, pos, lim, cap);
    this.hb = hb; // 数据数组
    this.offset = offset; // 初始偏移0
}

put

public ByteBuffer put(byte x) {
    hb[ix(nextPutIndex())] = x;
    return this;
}

// 增加偏移
protected int ix(int i) {
    return i + offset;
}

final int nextPutIndex() {
    if (position >= limit)
        throw new BufferOverflowException();
    return position++;
}

flip

public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
}

get

public byte get() {
    return hb[ix(nextGetIndex())];
}

protected int ix(int i) {
    return i + offset;
}

final int nextGetIndex() {
    if (position >= limit)
        throw new BufferUnderflowException();
    return position++;
}

rewind-重读

public final Buffer rewind() {
    position = 0;
    mark = -1;
    return this;
}

clear-清空

public final Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
}

compact-清空已读

public ByteBuffer compact() {
    System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
    position(remaining());
    limit(capacity());
    discardMark();
    return this;
}

public final int remaining() {
    return limit - position;
}

mark & reset

public final Buffer mark() {
    mark = position;
    return this;
}

public final Buffer reset() {
    int m = mark;
    if (m < 0)
        throw new InvalidMarkException();
    position = m;
    return this;
}

equals

public boolean equals(Object ob) {
    if (this == ob)
        return true;
    if (!(ob instanceof ByteBuffer))
        return false;
    ByteBuffer that = (ByteBuffer)ob;
    if (this.remaining() != that.remaining())
        return false;
    int p = this.position();
    for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
        if (!equals(this.get(i), that.get(j)))
            return false;
    return true;
}

Scatter & Gather

// Scattering Reads
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body   = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.read(bufferArray);
// Gathering Writes
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body   = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.write(bufferArray);

Selector

概述

// Selector创建
Selector selector = Selector.open();
channel.configureBlocking(false);(默认是true)
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);

监听事件类型

类型 SelectionKey 含义
Connect SelectionKey.OP_CONNECT channel成功连接到服务器
Accept SelectionKey.OP_ACCEPT server channel接收到连接
Read SelectionKey.OP_READ channel有数据可读
Write SelectionKey.OP_WRITE channel等待数据写入

SelectionKey

int interestSet = selectionKey.interestOps();
boolean isInterestedInAccept  = (interestSet & SelectionKey.OP_ACCEPT) != 0;
boolean isInterestedInConnect = (interestSet & SelectionKey.OP_CONNECT) != 0;
boolean isInterestedInRead    = (interestSet & SelectionKey.OP_READ) != 0;
boolean isInterestedInWrite   = (interestSet & SelectionKey.OP_WRITE) != 0;
int readySet = selectionKey.readyOps();
selectionKey.isAcceptable();
selectionKey.isConnectable();
selectionKey.isReadable();
selectionKey.isWritable();
Channel channel = selectionKey.channel(); // 和SelectionKey一对一
Selector selector = selectionKey.selector();
selectionKey.attach(theObject);
Object attachedObj = selectionKey.attachment();

SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject);

Selector选择通道

selector.select();

Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator keyIterator = selectedKeys.iterator();

while(keyIterator.hasNext()) {
    SelectionKey key = keyIterator.next();
    if(key.isAcceptable()) {
        // a connection was accepted by a ServerSocketChannel
    } else if (key.isConnectable()) {
        // a connection was established with a remote server
    } else if (key.isReadable()) {
        // a channel is ready for reading
    } else if (key.isWritable()) {
        // a channel is ready for writing
    }
    keyIterator.remove(); // 已处理的key需要手动移除
}

wakeUp()

close()

FileChannel

概述

打开FileChannel

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();

读数据

ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);

写数据

String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
    channel.write(buf);
}

关闭FileChannel

channel.close();

position方法

long pos = channel.position();
channel.position(pos + 123);

size方法

long fileSize = channel.size(); // 字节

truncate方法

channel.truncate(1024); // 截取文件前1024个字节,后面部分删除

force方法

channel.force(true); // true表示同时将文件元数据(权限信息等)写到磁盘上

Channel间数据传输

// transferFrom():源 -> FileChannel
RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
FileChannel fromChannel = fromFile.getChannel(); // 可以不是FileChannel
RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
FileChannel toChannel = toFile.getChannel();
long position = 0;
long count = fromChannel.size();
toChannel.transferFrom(fromChannel, position, count);
// transferTo():FileChannel -> 其他Channel
RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
FileChannel fromChannel = fromFile.getChannel();
RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
FileChannel toChannel = toFile.getChannel(); // 可以不是FileChannel
long position = 0;
long count = fromChannel.size();
fromChannel.transferTo(position, count, toChannel); // position是fromChannel的

SocketChannel

概述

打开

SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));

关闭

socketChannel.close();

读数据

ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = socketChannel.read(buf); // -1表示已读到流末尾,或者流已关闭

写数据

String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
   channel.write(buf);
}

非阻塞模式

socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
while(!socketChannel.finishConnect()){
    //wait, or do something else...
}

ServerSocketChannel

概述

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 打开
serverSocketChannel.bind(new InetSocketAddress(9999));
while(true){
    SocketChannel socketChannel = serverSocketChannel.accept();
    //do something with socketChannel...
}

关闭

serverSocketChannel.close();

监听

非阻塞模式

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false);
while(true){
    SocketChannel socketChannel = serverSocketChannel.accept();
    if(socketChannel != null){
       //do something with socketChannel...
    }
}

DatagramChannel

概述

打开

DatagramChannel channel = DatagramChannel.open();
channel.bind(new InetSocketAddress(9999));

接收数据

ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
channel.receive(buf); // 如果Buffer容不下所有数据,多出的数据被丢弃

发送数据

String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
int bytesSent = channel.send(buf, new InetSocketAddress("jenkov.com", 80));

连接到特定地址

channel.connect(new InetSocketAddress("jenkov.com", 80));
// 连接后,可以使用read()和write()方法,只是数据传送方面没有保证
int bytesRead = channel.read(buf);
int bytesWritten = channel.write(buf);

Pipe

概述

创建管道

Pipe pipe = Pipe.open();

写数据

Pipe.SinkChannel sinkChannel = pipe.sink();
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
    sinkChannel.write(buf);
}

读数据

Pipe.SourceChannel sourceChannel = pipe.source();
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = sourceChannel.read(buf);
上一篇 下一篇

猜你喜欢

热点阅读