java nio

 

package com.part01;
import java.nio.Buffer;//是内存区域,类似于数组
import java.nio.ByteBuffer;
import org.junit.Test;
public class Demo01 {

	@Test//在方法上加@意味着可以被测试     JUnit(导jar包)
	public void testFlip()
	{
		
		ByteBuffer buffer = ByteBuffer.allocate(10);
		info(buffer);
		buffer.put((byte) 23);
		buffer.put((byte) 24);
		info(buffer);

		buffer.flip();// 将 position放到0 limit放到原position 的位置, p--l之间是有效数据
		info(buffer);
	}
	
	@Test
	public void testClean()
	{
		ByteBuffer buffer=ByteBuffer.allocate(10);
		info(buffer);
		buffer.put((byte) 23);
		buffer.put((byte) 24);
		info(buffer);
		buffer.flip();
		info(buffer);
		
		//将p放到0    l和c放到最末尾,等待下一次读
		buffer.clear();
		info(buffer);
		
	}
   @Test
	public void testremain()
	{
		ByteBuffer buffer=ByteBuffer.allocate(10);
		info(buffer);
		buffer.put((byte) 23);
		buffer.put((byte) 24);
		info(buffer);
		buffer.flip();
		info(buffer);
		
		//在p ---l这间有没有东西
		if(buffer.hasRemaining())
		{
			//p--l之间的东西个数
			System.out.println(buffer.remaining());
		}

	}
   @Test
	public void testwind()
	{
		ByteBuffer buffer=ByteBuffer.allocate(10);
		info(buffer);
		buffer.put((byte) 23);
		buffer.put((byte) 24);
		info(buffer);
	    //将p设为0,值没有没变
		buffer.rewind();
		info(buffer);
		
		System.out.println(buffer.get());
		System.out.println(buffer.get());

	}

	public static void info(Buffer buf)
	{
		System.out.println("position:"+buf.position()+"----limit:"+buf.limit()+"----->capacity"+buf.capacity());
	}
}

依次测试testFlip,testClean,testremain,testwind结果如下:

position:0----limit:10----->capacity10
position:2----limit:10----->capacity10
position:0----limit:2----->capacity10

position:0----limit:10----->capacity10
position:2----limit:10----->capacity10
position:0----limit:2----->capacity10
position:0----limit:10----->capacity10

position:0----limit:10----->capacity10
position:2----limit:10----->capacity10
position:0----limit:2----->capacity10
2

position:0----limit:10----->capacity10
position:2----limit:10----->capacity10
position:0----limit:10----->capacity10
23
24


 

 

Bytebuffer与字符串之间的互转 

package com.part01;
//java.nio.charset.Charset类
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import org.junit.Test;
/*CharBuffer  decode(ByteBuffer bb)  将此 charset 中的字节解码成 Unicode 字符的便捷方法。 
  ByteBuffer encode(String str)   将此 charset中的字符串编码成字节的便捷方法。       
  static Charset forName(String charsetName)  返回指定 charset的charset 对象。 
  defaultCharset() 返回此 Java虚拟机的默认 charset。  */
         
public class Demo02
{
	@Test
   public void bytebuffer2string()//ByteBuffer转字符串
   {
	   ByteBuffer buf=ByteBuffer.allocate(10);
	   buf.put((byte)97);
	   buf.put((byte)98);
	   buf.put((byte)99);
	   buf.flip();
	   
	   CharBuffer charbuffer=Charset.defaultCharset().decode(buf);
	   System.out.println(charbuffer);
	   
   }
	
	@Test
	public void String2ByteBuffer()//字符串转ByteBuffer
	{
		String str="abc";
	    Charset charset=Charset.forName("utf-8");
	    ByteBuffer buf=charset.encode(str);
	    
	    System.out.println("position:"+buf.position()+"----limit:"+buf.limit()+"----->capacity"+buf.capacity());
	}
}

nio的思想和实现 

写东西

package com.part01;

import java.io.FileNotFoundException;
public class Demo03 {
	public static void main(String[] args) throws IOException 
	{
		FileOutputStream fo=new FileOutputStream("d:\\iodemo.txt");
		//输出流得到的FileChannel只能输出
		FileChannel  fc=fo.getChannel();
		String str="张三回来了吗";
     	ByteBuffer buf=Charset.defaultCharset().encode(str);
		
		fc.write(buf);
		fc.close();
		fo.close();
		System.out.println("OK");
	}
}

 等同于

package com.part01;

import java.io.FileOutputStream;
public class Demo04 {

	public static void main(String[] args) throws IOException 
	{
		FileOutputStream fo=new FileOutputStream("d:\\iodemo.txt");
		//输出流得到的FileChannel只能输出
		FileChannel  fc=fo.getChannel();
		
		String str="张三回来了吗";
		byte[] data=str.getBytes();
     	ByteBuffer buf=ByteBuffer.allocate(50);
     	buf.put(data);
     	buf.flip();//p--l之间的有效数
		fc.write(buf);//channel可以读写buffer
		fo.close();
		fc.close();
		System.out.println("OK");
	}
}

读东西

package com.part01;

import java.io.FileInputStream;
public class Demo05 {

	public static void main(String[] args) throws Exception{
    // Charset set=Charset.defaultCharset();
		//输入流得到的FileChannel只能写
     FileInputStream fi=new FileInputStream("d:\\iodemo.txt");
     FileChannel fc=fi.getChannel();
     
     ByteBuffer buf=ByteBuffer.allocate(4096);
     info(buf);
     
     int len=-1;
     
    while((len=fc.read(buf))>0)
    {
    	  info(buf);
    	  buf.flip();
    	  String str=Charset.defaultCharset().decode(buf).toString();
    	  System.out.println(str);
    	  buf.clear();//在下一次读之前 
    	 
    }
     fc.close();
     fi.close();
	}
	public static void info(Buffer buf)
	{
		System.out.println("position:"+buf.position()+"----limit:"+buf.limit()+"----->capacity"+buf.capacity());
	}
}
//在ByteBuffer里面拿数据的时候,一定要先flip
//从流中往ByteBuffer中读数据一定要clear

用java.nio来复制文件(虚拟内存映射模式)

package com.part10;

import java.io.FileInputStream;
//用java.nio来复制文件(虚拟内存映射模式)
public class Demo06 {

	public static void main(String[] args) throws IOException 
	{
		FileInputStream fi=new FileInputStream("D:\\tools\\eclipse-jee-oxygen-3-win32-x86_64.zip");
		FileOutputStream fo=new FileOutputStream("c:\\eclipse.zip");
		
		FileChannel  fic=fi.getChannel();
		FileChannel  foc=fo.getChannel();
		
		ByteBuffer buffer=ByteBuffer.allocate(4096);
		long start= System.currentTimeMillis();
		int len=-1;
		
          while((len=fic.read(buffer))>0)//读到数据,要把数据写到输出流
          {
        	  buffer.flip();
        	  foc.write(buffer);
        	  buffer.clear();//在下一次读之前
          }
          fic.close();
          foc.close();
          
          long end= System.currentTimeMillis();
          
          System.out.println((end-start)/1000.0);
	}

}

 

 

 

 

 

 

11-13
Java NIO(New I/O)是Java 1.4引入的新的I/O API,用于替代标准的Java I/O API。它提供了非阻塞I/O操作,能显著提高程序的性能和可扩展性,尤其适用于处理大量并发连接的场景。 ### 核心组件 - **Channel(通道)**:Channel是对传统I/O中流的模拟,用于在缓冲区和实体(如文件、套接字)之间传输数据。常见的Channel实现有FileChannel、SocketChannel、ServerSocketChannel和DatagramChannel等。例如,FileChannel用于文件读写,SocketChannel用于TCP网络通信。 - **Buffer(缓冲区)**:Buffer是一个用于存储特定基本类型数据的容器。所有的缓冲区都是Buffer抽象类的子类,如ByteBuffer、CharBuffer、IntBuffer等。使用时,数据先被写入Buffer,再从Buffer读取到Channel,反之亦然。 - **Selector(选择器)**:Selector是Java NIO实现非阻塞I/O的关键。它允许一个线程处理多个Channel的I/O事件。通过将多个Channel注册到一个Selector上,Selector可以不断轮询这些Channel,当某个Channel有可用的I/O操作时,就会被Selector选中,从而实现单线程处理多个连接的目的。 - **SelectionKey(选择键)**:SelectionKey用于维护Selector和SelectableChannel的关系,每个Channel注册到Selector时都会产生一个SelectionKey,它聚合了Channel和Selector,有点类似EventKey。通过SelectionKey可以获取对应的Channel和Selector,还可以设置和查询感兴趣的I/O事件类型,如读、写、连接和接受连接事件等 [^1]。 ### 使用指南 #### 1. 使用FileChannel进行文件读写 ```java import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class FileChannelExample { public static void main(String[] args) { try (FileInputStream fis = new FileInputStream("input.txt"); FileOutputStream fos = new FileOutputStream("output.txt"); FileChannel inChannel = fis.getChannel(); FileChannel outChannel = fos.getChannel()) { ByteBuffer buffer = ByteBuffer.allocate(1024); while (inChannel.read(buffer) != -1) { buffer.flip(); // 切换为读模式 outChannel.write(buffer); buffer.clear(); // 清空缓冲区,准备下一次写入 } } catch (IOException e) { e.printStackTrace(); } } } ``` #### 2. 使用Selector实现非阻塞网络编程 ```java 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.Iterator; import java.util.Set; public class NioServerExample { public static void main(String[] args) { try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); Selector selector = Selector.open()) { serverSocketChannel.socket().bind(new InetSocketAddress(8080)); serverSocketChannel.configureBlocking(false); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { int readyChannels = selector.select(); if (readyChannels == 0) continue; Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isAcceptable()) { ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel(); SocketChannel socketChannel = serverChannel.accept(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int bytesRead = socketChannel.read(buffer); if (bytesRead > 0) { buffer.flip(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); System.out.println(new String(data)); } } keyIterator.remove(); } } } catch (IOException e) { e.printStackTrace(); } } } ``` ### 原理 Java NIO的非阻塞I/O原理基于操作系统的I/O多路复用机制。在传统的阻塞I/O模型中,一个线程只能处理一个连接,当线程在等待某个连接的数据时会被阻塞,无法处理其他连接。而在Java NIO中,Selector利用操作系统提供的I/O多路复用功能,如Linux的select、poll和epoll,通过一个线程监控多个Channel的I/O状态。当某个Channel有数据可读或可写时,Selector会感知到并通知应用程序进行相应的处理,从而实现单线程处理多个连接,提高了系统的并发处理能力。 ### 应用场景 - **网络编程**:在构建高性能的网络服务器时,如Web服务器、聊天服务器、游戏服务器等,Java NIO的非阻塞I/O特性可以显著减少线程数量,降低系统资源消耗,提高服务器的并发处理能力。 - **文件处理**:对于大文件的读写操作,使用FileChannel和ByteBuffer可以提高文件读写的效率,尤其是在需要随机访问文件内容时。 - **实时数据处理**:在处理实时数据流时,如视频流、音频流等,Java NIO可以高效地处理数据的传输和处理,确保数据的实时性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值