IO和NIO 区别:
1. IO面向流(stream),流是单向的,NIO面向的是(buffer),管道(channel)双向的。
2. IO是阻塞式,NIO是非阻塞式的(NIO多了一个选择器(selector))
缓冲区类型:
ByteBuffer/CharBuffer/ShortBuffer/IntBuffer/LongBuffer/FloatBuffer/DoubleBuffer
缓冲区的四大属性:
capacity: 表示缓冲区最大的存取的容量,一旦申请,不能修改。
limit:表示缓冲区中可以操作的数据的大小。(limit后面的数据不能进行读写)。
postion: 表示缓冲区中正在操作的位置。
mark: 记录当前position的位置,可以通过reset()方法回到mark标记的位置。
position < limit < capacity;
put(): 存数据
flip(): 从写模式切换到读模式
get():取数据
rewind: 可重复读
clear:清空缓冲区,数据存于被遗忘的状态
isDirect: 是否是直接缓冲区
注意:分配缓存区分为直接缓存区(操作系统的直接内存上分配空间)和非直接缓冲区(JVM内存分配的
空间)
通道(channel)类型:
用于源节点和目标节点的连接,在javaNIO中实现缓冲区的传输。
FileChannel: 本地文件的通道
SocketChannel: 网络文件的通道 TCP
ServerSocketChannel:网络文件的通道 TCP
DatagramChannel: 网络文件的通道 UDP
获取channel方法:
1. java 针对支持通道的类提供了 getChannel() 方法
本地IO:
FileInputStream/ FileOutputStream / RandomAccessFile
网络IO:
Socket/ ServerSocket/DatagramSocket
2. 在JDK1.7 中的NIO.2 针对各个通道提供了静态方法open() 获取通道
3. 在JDK1.7 中的NIO.2 的Files 工具类newByteChannel()
通道之间的数据传输:
transferTo;
transferFrom;
ifc.transferTo(0, ifc.size(), ofc);
ofc.transferFrom(ifc, 0,ifc.size());
分散(scatter)读取和聚集(gather)写入:
将通道中数据读到多个缓冲区中;将多个缓冲区的数据写入通道中,通过buffer数组实现
非阻塞式适用于网络传输:
java.nio.channels.Channel
|-- SelectableChannel
|-- SocketChannel
|-- ServerSocketChannel
|-- DatagramChannel
|-- Pipe.SinkChannel
|-- Pipe.SourceChannel
阻塞式:
package com.nio.day02;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import org.junit.Test;
public class TestBolckNIO {
@Test
public void client() throws IOException{
// 获取通道
SocketChannel sChannel = SocketChannel.open(new InetSocketAddress
("127.0.0.1",9898));
FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"),
StandardOpenOption.READ);
// 分配缓冲区
ByteBuffer dst = ByteBuffer.allocate(1024);
// 读取本地文件
while(inChannel.read(dst) != -1){
dst.flip();
sChannel.write(dst);
dst.clear();
}
inChannel.close();
sChannel.close();
}
@Test
public void server() throws IOException{
ServerSocketChannel ssChannel = ServerSocketChannel.open();
ssChannel.bind(new InetSocketAddress(9898));
FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"),
StandardOpenOption.WRITE,StandardOpenOption.CREATE);
SocketChannel sChannel = ssChannel.accept();
ByteBuffer buf = ByteBuffer.allocate(1024);
while(sChannel.read(buf) != -1){
buf.flip();
outChannel.write(buf);
buf.clear();
}
outChannel.close();
sChannel.close();
}
}
非阻塞式:
package com.nio.day01;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import org.junit.Test;
public class TestIO {
// 客户端
@Test
public void client() throws IOException{
// 获取通道
SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",9898));
// 切换成非阻塞模式
sChannel.configureBlocking(false);
//
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.put((new Date()).toString().getBytes());
buf.flip();
sChannel.write(buf);
buf.clear();
sChannel.close();
}
@Test
public void server() throws IOException{
//
ServerSocketChannel ssChannel = ServerSocketChannel.open();
ssChannel.configureBlocking(false);
ssChannel.bind(new InetSocketAddress(9898));
// 创建选择器
Selector seletor = Selector.open();
// 监控选择器控制 通道的什么状态。
ssChannel.register(seletor, SelectionKey.OP_ACCEPT);
// 轮询式的获取选择器上已经"准备就绪"的事件
while(seletor.select() > 0){
// 获取当前选择器中的所有注册的选择键
Iterator<SelectionKey> it = seletor.selectedKeys().iterator();
while(it.hasNext()){
// 获取准备就绪的事件
SelectionKey sk = it.next();
// 判断什么事件准备就绪
if(sk.isAcceptable()){
SocketChannel sChannel = ssChannel.accept();
sChannel.configureBlocking(false);
sChannel.register(seletor, SelectionKey.OP_READ);
}else if(sk.isReadable()){
SocketChannel sChannel = (SocketChannel)sk.channel();
ByteBuffer buf = ByteBuffer.allocate(1024);
int len = 0;
while((len = sChannel.read(buf)) > 0){
buf.flip();
System.out.println(new String(buf.array(),0 ,len));
buf.clear();
}
}
// 取消选择键
it.remove();
}
}
}
}