java中的nio

1.什么是nio

nio是一个非阻塞的IO。之前学的IO是面向流的一种技术。而nio是面向缓冲区的一种技术。采用通道传输。nio可以高效的进行文件的读写操作(之所以速度的提高来自于操作系统所执行的IO方式:缓冲区和通道)。

2.缓冲区

缓冲区的API除了没有boolean对应的Buffer,其他基本类型都有,如IntBuffer,ByteBuffer,FloatBuffer等。

缓冲区的原理:

缓冲区在java nio中负责数据的存取。缓冲区就是数组,用于存取不同类型的数据。

缓冲区的属性:

初始化图:(分配空间为7的容量)


capacity:容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。

limit:界限,表示缓冲区中可以操作数据的大小。(limit后数据不能读写)
position:位置,表示缓冲区中正在操作数据的位置。

public class TestBuffer {
	
	private void printProperties(int position,int limit,int capacity){
		System.out.println("capacity:"+capacity);
		System.out.println("limit:"+limit);
		System.out.println("position:"+position);
	}
       @Test
    public void test1(){
        String str ="abcde";
        
        //分配一个指定大小的缓冲区
        ByteBuffer buf =ByteBuffer.allocate(1024);
        System.out.println("----------初始化------------");
        printProperties(buf.position(),buf.limit(),buf.capacity());
       }
}
结果:



put方法:存入元素到缓冲区


System.out.println("-----------put------------");
buf.put(str.getBytes());
printProperties(buf.position(),buf.limit(),buf.capacity());
结果:



flip方法:用来切换到读模式

buf.flip();
printProperties(buf.position(),buf.limit(),buf.capacity());
System.out.println("----------get-------------");
byte[] dest =new byte[buf.limit()];
buf.get(dest);
printProperties(buf.position(),buf.limit(),buf.capacity());
结果:



rewind方法:重复读,将位置设置为零并丢弃标记。

System.out.println("----------rewind-------------");
buf.rewind();
printProperties(buf.position(),buf.limit(),buf.capacity());
结果:



clear方法:清空缓冲区,将位置设置为零,限制设置为该容量,并且丢弃标记。

System.out.println("----------clear-------------");
buf.clear();
printProperties(buf.position(),buf.limit(),buf.capacity());
结果:


mark和reset方法

mark属性:标记,表示记录当前position的位置。可以通过reset()恢复到mark的位置。reset 恢复到mark标记的位置

@Test
public void test2(){
	String str ="efghijk";
	ByteBuffer buf =ByteBuffer.allocate(1024);
	printProperties(buf.position(), buf.limit(), buf.capacity());
	buf.put(str.getBytes());
	buf.flip();
	byte[] dest =new byte[buf.limit()];
	buf.get(dest,0,3);
	System.out.println(new String(dest,0,2));
	System.out.println(buf.position());
	//mark
	buf.mark();
	buf.get(dest,2,2);
	System.out.println(new String(dest,2,2));
	System.out.println(buf.position());
		
	//reset 恢复到mark标记的位置
	buf.reset();
	System.out.println(buf.position());
}
结果:



直接缓冲区与间接缓冲区的区别:
间接缓冲区:通过allocate方法分配缓冲区,将缓冲区建立在jvm内存中
直接缓冲区:通过allocateDirect方法分配直接缓冲区,将缓冲区建立在操作系统的物理内存中。


3.通道

通道在java nio中负责缓冲区中数据的传输。

主要实现类:

①FileChannel:用于操作本地的通道。

②SocketChannel:用于操作网络TCP协议的通道。

③ServerSocketChannel:用于操作网络TCP协议的通道。

④DatagramChannel:用于操作网络UDP协议的通道。

获取通道:

本地IO方式:FileInputStream/FileOutputStream、RandomAccessFile

网络IO方式:Socket、ServerSocket、DatagramSocket

示例:

方式一:使用文件流来获取通道的方式来复制文件

@Test
public void testChannel() throws Exception{
	FileInputStream fis =new FileInputStream("C:\\Users\\Administrator\\Desktop\\触发器.txt");
	FileOutputStream fos =new FileOutputStream("C:\\Users\\Administrator\\Desktop\\触发器1.txt");
		
	FileChannel fic =fis.getChannel();
	FileChannel foc =fos.getChannel();
		
	ByteBuffer buf =ByteBuffer.allocate(1024);
			
	while(fic.read(buf) !=-1){
		buf.flip();
		foc.write(buf);
		buf.clear();
	}
	foc.close();
	fic.close();
	fos.close();
	fis.close();
}
结果:


方式二:将文件区域直接映射到内存中来创建

@Test
public void testChannelByOpen() throws Exception{
	FileChannel inChannel =FileChannel.open(Paths.get("C:\\Users\\Administrator\\Desktop\\触发器.txt"), StandardOpenOption.READ);
	FileChannel outChannel =FileChannel.open(Paths.get("C:\\Users\\Administrator\\Desktop\\触发器2.txt"),StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
		
	//直接字节缓冲区,其内容是文件的内存映射区域:将此通道的文件区域直接映射到内存中。
	MappedByteBuffer inMappedBuf =inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
	MappedByteBuffer outMapperBuf =outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
	//直接对缓冲区进行读写操作
	byte[] dest =new byte[inMappedBuf.limit()];
	inMappedBuf.get(dest);
	outMapperBuf.put(dest);
		
	outChannel.close();
	inChannel.close();
}
结果:


4.字符编码与解码

示例:

@Test
public void testCharset() throws IOException{
	Charset cs1 =Charset.forName("UTF-8");
	//获取编码器
     CharsetEncoder ce =cs1.newEncoder();
     //获取解码器
     CharsetDecoder cd =cs1.newDecoder();
		
	CharBuffer cBuf =CharBuffer.allocate(1024);
	cBuf.put("张无忌");
	cBuf.flip();
	//编码
	ByteBuffer eBuf =ce.encode(cBuf);
	while(eBuf.hasRemaining()){
		System.out.println(eBuf.get());
	}
	//解码
	eBuf.flip();
	CharBuffer result =cd.decode(eBuf);
	System.out.println(result.toString());
}
结果:


5.阻塞式网络NIO

客户端发送本地文件数据:

@Test
public void initClient() throws IOException{
	//获取网络NIO的通道
	SocketChannel socketChannel =SocketChannel.open(new InetSocketAddress("localhost", 8888));
	//获取本地文件对应的文件通道
	FileChannel inputChannel =FileChannel.open(Paths.get("C:\\Users\\Administrator\\Desktop\\1.jpg"), StandardOpenOption.READ);
	//分配1024大小的缓冲区
	ByteBuffer buf =ByteBuffer.allocate(1024);
	//循环读取本地文件通道中的缓冲区中的数据,写入到网络通道缓冲区中
	while(inputChannel.read(buf) !=-1){
		buf.flip();
		socketChannel.write(buf);
		buf.clear();
	}
	socketChannel.shutdownOutput();
	//发送成功提示
	int len =0;
	while((len =socketChannel.read(buf)) !=-1){
		buf.flip();
		System.out.println(new String(buf.array(),0,len));
		buf.clear();
	}
	inputChannel.close();
	socketChannel.close();
}
服务端接收数据:

@Test
public void initServer() throws IOException{
    ServerSocketChannel ssChannel =ServerSocketChannel.open();
    FileChannel outChannel =FileChannel.open(Paths.get("C:\\Users\\Administrator\\Desktop\\2.jpg"), StandardOpenOption.WRITE,StandardOpenOption.CREATE);
    ssChannel.bind(new InetSocketAddress(8888));
        
    SocketChannel socketChannel =ssChannel.accept();
    ByteBuffer buf =ByteBuffer.allocate(1024);
    while(socketChannel.read(buf) !=-1){
        buf.flip();
        outChannel.write(buf);
        buf.clear();
    }
        
    buf.put("服务端接收客户端的数据成功".getBytes());
    buf.flip();
    socketChannel.write(buf);
        
    socketChannel.close();
    outChannel.close();
    ssChannel.close();
}
结果:



6.非阻塞网络NIO

客户端发送数据:

@Test
public void initClient() throws IOException{
	SocketChannel socketChannel =SocketChannel.open(new InetSocketAddress("localhost", 8989));
	socketChannel.configureBlocking(false);
	ByteBuffer buf =ByteBuffer.allocate(1024);
	Scanner scanner =new Scanner(System.in);
	while(scanner.hasNext()){
		String content =scanner.next();
		buf.put((new Date()+" : "+content).getBytes());
		buf.flip();
		socketChannel.write(buf);
		buf.clear();
	}
	socketChannel.close();
}
服务端接收数据:

@Test
public void initServer() throws IOException{
	ServerSocketChannel serverSocketChannel =ServerSocketChannel.open();
	serverSocketChannel.configureBlocking(false);
	serverSocketChannel.bind(new InetSocketAddress(8989));
	Selector selector =Selector.open();
	serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
	while(selector.select() >0){
		Iterator<SelectionKey> it =selector.selectedKeys().iterator();
		while(it.hasNext()){
			SelectionKey key =it.next();
			if(key.isAcceptable()){
				SocketChannel socketChannel =serverSocketChannel.accept();
				socketChannel.configureBlocking(false);
				socketChannel.register(selector, SelectionKey.OP_READ);
			}else if(key.isReadable()){
				SocketChannel socketChannel =(SocketChannel) key.channel();
				ByteBuffer buf =ByteBuffer.allocate(1024);
				int len =0;
				while((len =socketChannel.read(buf))>0){
					buf.flip();
					System.out.println(new String(buf.array(),0,len));
					buf.clear();
				}
			}
			it.remove();
		}
	}
}
结果:





7.使用UDP协议的网络NIO

服务端:

@Test
public void server() throws IOException{
	DatagramChannel dc = DatagramChannel.open();	
	dc.configureBlocking(false);	
	dc.bind(new InetSocketAddress(9898));
	Selector selector = Selector.open();
	dc.register(selector, SelectionKey.OP_READ);
	while(selector.select() > 0){
		Iterator<SelectionKey> it = selector.selectedKeys().iterator();
		while(it.hasNext()){
			SelectionKey sk = it.next();
			if(sk.isReadable()){
				ByteBuffer buf = ByteBuffer.allocate(1024);
					
				dc.receive(buf);
				buf.flip();
				System.out.println(new String(buf.array(), 0, buf.limit()));
				buf.clear();
			}
		}
		it.remove();
	}
}
客户端:

@Test
public void client() throws IOException{
	DatagramChannel dc = DatagramChannel.open();
	dc.configureBlocking(false);
	ByteBuffer buf = ByteBuffer.allocate(1024);	
	Scanner scan = new Scanner(System.in);
	while(scan.hasNext()){
		String str = scan.next();
		buf.put((new Date().toString() + " : " + str).getBytes());
		buf.flip();
		dc.send(buf, new InetSocketAddress("localhost", 9898));
		buf.clear();
	}
	dc.close();
}
结果:








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值