NIO_NIO与IO区别
传统的IO:单向的
NIO模型:双向的
NIO_缓冲区(Buffer)的数据存取
package com.nio;
import java.nio.ByteBuffer;
public class NioSample {
public static void main(String[] args) {
String str="测试数据";
ByteBuffer buffer=ByteBuffer.allocate(10);//开辟缓存空间
System.out.println("位置指针"+buffer.position()+"容量指针"+buffer.capacity()+"分割指针"+buffer.limit());
buffer.put(str.getBytes());
System.out.println("存过数据后--位置指针"+buffer.position()+"容量指针"+buffer.capacity()+"分割指针"+buffer.limit());
buffer.flip();//重置指针
System.out.println("重置filp后--位置指针"+buffer.position()+"容量指针"+buffer.capacity()+"分割指针"+buffer.limit());
byte[] b=new byte[buffer.limit()];
while(buffer.hasRemaining()) {
buffer.get(b);
System.out.println(new String(b));
}
buffer.clear();//清空缓存buffer
}
}
NIO_直接缓冲区与非直接缓冲区
NIO_通道(Channel)的原理与获取
package com.nio;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NIOchannel {
public static void main(String[] args) throws IOException {
//读取本地文件到控制台。使用通道 channel
//管道类似于火车轨道。但是还需要火车 buffer
//流是单向的。管道是双向的。能读能写
//创建输入字节流路径
FileInputStream fis=new FileInputStream("a.txt");
//建立通道
FileChannel channel=fis.getChannel();//通道是建立在字节流之上
//开辟缓存空间 火车
ByteBuffer buffer=ByteBuffer.allocate(20);//开辟缓存空间 并且分配大小
ByteArrayOutputStream bos=new ByteArrayOutputStream();//输出流
int data=0;
//使用通道channel读缓存buffer的内容
while((data=channel.read(buffer))!=-1) {
buffer.flip();//刷新指针
while(buffer.hasRemaining()) {//判断缓存是否有数据
bos.write(buffer.get());//缓存 一个字节一个字节向外拿。存储到输出流中
}
buffer.clear();//清空缓存
}
//读取到的内容
System.out.println(new String(bos.toByteArray()));
channel.close();
}
}
NIO_通道的数据传输与内存映射文件
public class TestChannel {
//1.利用通道来完成文件的复制
@Test
public void test1() {
FileInputStream fis = null;
FileOutputStream fos = null;
FileChannel inChannel = null;
FileChannel outChannel = null;
try {
fis = new FileInputStream("1.jpg");
fos = new FileOutputStream("3.jpg");
//2.获取通道
inChannel = fis.getChannel();
outChannel = fos.getChannel();
//3.分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
//4.将通道中的数据存入缓冲区中读取数据
while (inChannel.read(buf) != -1) {
buf.flip();//切换成读取数据的模式
//5.将缓冲区中的数据再写入到通道
outChannel.write(buf);
//清空缓冲区
buf.clear();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if ( outChannel != null) {
try {
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inChannel!=null) {
try {
inChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos!=null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis!=null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
NIO_Pipe管道
给管道加锁 tryLock
package com.nio;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.concurrent.TimeUnit;
public class NIOchannelLock {
public static void main(String[] args) throws IOException, InterruptedException {
FileOutputStream fos=new FileOutputStream("a.txt");
FileChannel channel=fos.getChannel();
//然后给管道加锁
FileLock lock=channel.tryLock();
//判断锁是否添加成功
if(lock!=null) {
System.out.println("channel加锁成功");
TimeUnit.SECONDS.sleep(10);
//解锁
lock.release();
System.out.println("解锁成功");
}
}
}
服务端ServerSocketChannel
package com.selector;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestServerSocketChannel {
public void start() throws IOException {
//创建线程池 固定长度的线程池
//线程池种类: 固定长度。单例(只有一个线程)。基于缓存的
ExecutorService threadpool=Executors.newFixedThreadPool(10);//10个线程池
//创建服务端通道
ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
//设置通道是否为阻塞。
serverSocketChannel.configureBlocking(false);
//设置服务端端口号
serverSocketChannel.bind(new InetSocketAddress(ServerInfo.PORT));
//创建选择器
Selector select=Selector.open();
//第二个参数表示注册的时机 有读取数据的时机 写入数据的时机 请求连接就注册
serverSocketChannel.register(select, SelectionKey.OP_ACCEPT);//表示请求的时候就注册到选择器
//定义一个操作状态,读 写 请求 的返回值 做比较
int requestStatus=0;//所有的操作状态都是大于0的
//如果状态码大于0,表示已经进行了操作
while(select.select()>0) {
//但是我们不知道操作了什么。获得所有的状态码。
Set<SelectionKey> selectedKeys=select.selectedKeys();
//把状态码进行遍历.迭代器
Iterator<SelectionKey> iterator =selectedKeys.iterator();
while(iterator.hasNext()) {
//拿到集合中存在的 选择器的key
SelectionKey next=iterator.next();
//判断是否是连接状态
if(next.isAcceptable()) {
//处理连接请求 返回的是连接对象 套接字通道
SocketChannel socketChannel=serverSocketChannel.accept();
//如果不等于空 连接成功
if(socketChannel!=null) {
threadpool.submit(new ThreadNio(socketChannel));
}
}
}
}
threadpool.shutdown();//终结线程池 这个关闭表示 温柔关闭 如果当前线程池内有正在运行的线程。.等待所有线程运行完在关闭
//threadPool.shutdownNow();//强硬关闭 如果线程池内还有任务 未执行的 移除队列 已经在执行的 尝试停止
serverSocketChannel.close();
}
public static void main(String[] args) throws IOException {
new TestServerSocketChannel().start();
}
}
服务端线程run方法ThreadNio
package com.selector;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class ThreadNio implements Runnable {
private SocketChannel socketChannel;
private boolean flag=true;
public ThreadNio(SocketChannel socketChannel) {
this.socketChannel = socketChannel;
}
@Override
public void run() {
ByteBuffer bytebuffer=ByteBuffer.allocate(1024);
try {
while (flag) {
bytebuffer.clear();
int count = this.socketChannel.read(bytebuffer);
//将读取到的信息转为字符串
String readMessage = new String(bytebuffer.array(), 0, count);
System.out.println("客户端发送的信息" + readMessage);
String writeMessage = "服务器发送的信息" + readMessage;
if ("exit".equalsIgnoreCase(readMessage)) {
System.out.println("[拜拜!]");
flag = false;
}
bytebuffer.clear();
bytebuffer.put(writeMessage.getBytes());
bytebuffer.flip();
this.socketChannel.write(bytebuffer);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
this.socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端SocketChannel
package com.selector;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class Client {
public static void main(String[] args) throws IOException {
//获得一个客户端通道
SocketChannel socketChannel=SocketChannel.open(new InetSocketAddress(ServerInfo.ADDRESS, ServerInfo.PORT));
//是否为阻塞模式
//socketChannel.configureBlocking(false);
//创建缓存区
ByteBuffer buffer=ByteBuffer.allocate(1024);
while(true) {
buffer.clear();
String str=InputUtil.getInput("请输入信息");
buffer.put(str.getBytes());
buffer.flip();
socketChannel.write(buffer);
buffer.clear();
if("exit".equals(str)) {
break;
}
int data=socketChannel.read(buffer);
System.out.println(new String(buffer.array(),0,data));
}
socketChannel.close();
}
}
选择器 的应用Selector
inputUtil工具类
package com.selector;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputUtil {
public static BufferedReader READER=new BufferedReader(new InputStreamReader(System.in));
public static String getInput(String str){
String result="";
if("".equals(result) || result==null) {
System.out.println(str);
try {
result=READER.readLine();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
}