NIO通过通道来读写数据
Channel有以下实现类
FileChannel:文件读写通道。
DatagramChannel:通过UDP读写网络中的数据。
SocketChannel:通过TCP读写网络中的数据。
ServerSocketChannel:监听新进来的TCP连接,对每个新进来的连接都会创建一个SocketChannel。
Channel读取数据的方式与Buffer相似,也存在position定位。如定位末尾
fileChannel.position(fileChannel.size())
通道之间,可以通过transferTo、transferFrom来进行数据的复制。
transferTo(position, count, toChannel);
数据传输到toChannel 通道,position是复制开始的坐标、count是复制长度、toChannel是复制的目标通道。
transferFrom(position, count, fromChannel);
从fromChannel 通道复制数据,position是复制开始的坐标、count是复制长度、fromChannel是通道对象。
例子
这个例子是将fromFile.txt文件复制到toFile.txt中。在这个复制中,toFile.txt文件中在count内的内容将被改写,而超过count的内容将保持不变。
@Test
public voidtransferTo() throwsIOException {
RandomAccessFile fromfile= new RandomAccessFile("src/main/resources/fromFile.txt", "r");
FileChannel fromChannel= fromfile.getChannel();
RandomAccessFile tofile= new RandomAccessFile("src/main/resources/toFile.txt", "rw");
FileChannel toChannel= tofile.getChannel();
fromChannel.transferTo(0, fromChannel.size(), toChannel);
}
Selector选择器可以监听多个Channel通道感兴趣的事情(read、write、accept(服务端接收)、connect,实现一个线程管理多个Channel,节省线程切换上下文的资源消耗。Selector只能管理非阻塞的通道,FileChannel是阻塞的,无法管理。
Selector:选择器对象,通道注册、通道监听对象和Selector相关。
SelectorKey:通道监听关键字,通过它来监听通道状态。
监听注册在Selector
socketChannel.register(selector, SelectionKey.OP_READ);
监听的事件有
OP_ACCEPT: 接收就绪,serviceSocketChannel使用的
OP_READ: 读取就绪,socketChannel使用
OP_WRITE: 写入就绪,socketChannel使用
OP_CONNECT: 连接就绪,socketChannel使用
可以用过OP_READ| OP_WRITE方式注册多个事件
socketChannel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE|SelectionKey.OP_CONNECT);
public classSelectorTest {
Selectorselector= null;
SocketChannelsocketChannel = null;
@Before
public void before(){
try {
selector = Selector.open();
socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1",9999));
socketChannel.configureBlocking(false);
}catch(IOException e) {
e.printStackTrace();
}
}
@Test
public void selectorTest() throws IOException {
socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT);
while (true) {
int n = selector.select();
if (n == 0)
continue;
Iterator keyIterator= selector.selectedKeys().iterator();
while (keyIterator.hasNext()) {
SelectionKey key1= (SelectionKey) keyIterator.next();
if (key1.isAcceptable()) {
System.out.println("服务端接收就绪");
}else if(key1.isConnectable()){
System.out.println("客户端连接接续");
}else if(key1.isReadable()){
System.out.println(key1.hashCode() + "读取就绪");
SocketChannel socketChannel1= (SocketChannel) key1.channel();
ByteBuffer bBuffer= ByteBuffer.allocate(48);
for (int readSize = socketChannel1.read(bBuffer); readSize != -1; readSize = socketChannel1
.read(bBuffer)) {
if (readSize == 0)
continue;
bBuffer.flip();
System.out.println(Charset.forName("UTF-8").decode(bBuffer));
bBuffer.clear();
}
socketChannel1.close();
}elseif(key1.isWritable()){
System.out.println(key1.hashCode() + "写入就绪");
}
keyIterator.remove();
}
}
}
}