NIO_缓冲区和通道

Java在1.5之后提供了新的IO通信框架,NIO和普通IO的区别是NIO是基于channel和Buffer来进行操作的,这和传统的IO是有一些区别的,传统的IO是基于管道流的方式进行数据传输,而NIO的数据首先需要添加到buffer中,之后通过channel来进行传输。

Buffer缓冲区
不同的数据类型都是自己的缓冲区,但是在NIO中比较通用的是ByteBuffer,通过allocate和allocateDirect来创建缓冲区,第一种缓冲区是在堆中创建,第二种缓冲区会在操作系统的内存中创建,第二种缓冲区占用的是系统的内存资源,创建和销毁都需要一定的开销,在使用channel的时候能够提高一定的效率。

Channel
NIO中是通过Channel来传输buffer的数据,操作和IO类似,但多了将Buffer添加到Channel的步骤
一个读取文件的实例:

public class TestChannel {
	public static void main(String[] args) {
		FileChannel fc = null;
		try {
			// 创建文件管道
			fc = FileChannel.open(Paths.get("d:/data/11.txt"), StandardOpenOption.READ);
			// 创建buffer
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			int len = 0;
			byte[] buf = new byte[1024];
			// 只要能够从缓冲区中读取数据
			while ((len = fc.read(buffer)) > 0) {
				// 重置缓冲区
				buffer.flip();// nio中提供了flip()方法来反转缓冲区,反转之后limit会指向当前缓冲区的最大值。
				// 从缓冲区读取到字节数组中
				buffer.get(buf, 0, len);
				// 输出字节数组的值
				System.out.println(new String(buf, 0, len));
				// 重置缓冲区
				buffer.clear();
			}
			// fc.read(buffer);

		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (fc != null)
					fc.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}
}

实现文件copy 的实例

public class TestChannel02 {
    public static void main(String[] args) {
        FileChannel fin = null;
        FileChannel fout = null;
        ByteBuffer buf = null;
        try {
            //创建两个通道,一个读数据,一个写数据
            fin = FileChannel.open(Paths.get("d:/data/aa.txt"), StandardOpenOption.READ);
            //设置文件如果不存在就创建,并且可以进行写操作
             fout = FileChannel.open(Paths.get("d:/data/bb.txt"),StandardOpenOption.CREATE,StandardOpenOption.WRITE);
            //创建缓冲区来作为数据的中转
            buf = ByteBuffer.allocate(1024);
            while((fin.read(buf))>0) {
                buf.flip();
                fout.write(buf);
                buf.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(fin!=null) fin.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(fout!=null) fout.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在NIO中提供了transferTo方法来快速将两个通道进行转换

public class TestChannel03 {
	public static void main(String[] args) {
		FileChannel fin = null;
		FileChannel fout = null;

		try {
			fin = FileChannel.open(Paths.get("d:/data/aa.txt"), StandardOpenOption.READ);
			fout = FileChannel.open(Paths.get("d:/data/bb.txt"), StandardOpenOption.CREATE_NEW,
					StandardOpenOption.WRITE);
			// 通过transferTo可以将两个通道对接
			fin.transferTo(0, fin.size(), fout);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (fin != null)
					fin.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (fout != null)
					fout.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

NIO主要基于网络通信中
传统的 io 和 NIO 的区别,通过见图表达
在这里插入图片描述
在这里插入图片描述

以下是NIO 的网络编程实例

public class NioSocketDemo {
	private Selector selector;

	public static void main(String[] args) throws IOException {
		NioSocketDemo nd = new NioSocketDemo();
		nd.initServer(8888);
		nd.listenSelector();
	}

	public void initServer(int port) throws IOException {
		ServerSocketChannel schannel = ServerSocketChannel.open();
		schannel.configureBlocking(false);
		schannel.socket().bind(new InetSocketAddress(port));

		this.selector = Selector.open();
		schannel.register(selector, SelectionKey.OP_ACCEPT);

		System.out.println("服务已经启动了");
	}

	public void listenSelector() throws IOException {
		while (true) {
			this.selector.select();// 阻塞点 真正关心的阻塞点是读取数据
			Iterator<SelectionKey> set = selector.selectedKeys().iterator();
			while (set.hasNext()) {
				SelectionKey key = set.next();
				set.remove();
				handler(key);
			}
		}
	}

	private void handler(SelectionKey key) throws IOException {
		if (key.isAcceptable()) {
			ServerSocketChannel serverChanel = (ServerSocketChannel) key.channel();
			SocketChannel sc = serverChanel.accept();
			sc.configureBlocking(false);// 设置非阻塞,
			sc.register(selector, SelectionKey.OP_READ);
		} else if (key.isReadable()) {
			SocketChannel sc = (SocketChannel) key.channel();
			ByteBuffer bb = ByteBuffer.allocate(1024);
			int c = sc.read(bb);
			if (c > 0) {
				String str = new String(bb.array(), "GBK").trim();
				System.out.println("服务端收到数据:" + str);
			} else {
				System.out.println("客户端关闭了......");
				key.cancel();
			}
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值