java nio 异步操作 (一)

先来看些nio基础的类库关系图 用pd大致画了下

相关的图片

上面是一些理论的关系图 下面是一些测试代码  相关的代码 都加了必要的注释

文件通道  FileChannel

package test;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * 文件通道测试类
 * FileChannel文件通道只能使用阻塞模式
 * AsynchronousFileChannel 异步 可以使用异步模式
 * A FileChannel cannot be set into non-blocking mode. It always runs in blocking mode
 * @author u1
 *
 */
public class BasicFileChannel {

	RandomAccessFile randomAccessFile;
	FileChannel channel;
	ByteBuffer buffer;
	AsynchronousFileChannel fileChannel;

	@Before
	public void before() throws IOException{
		randomAccessFile=new RandomAccessFile(ClassLoader.getSystemResource("selector.txt").getFile(), "rw");
		channel=randomAccessFile.getChannel();
		//强制刷新
		channel.force(true);
		buffer=ByteBuffer.allocate(102400);
		String aaa=buffer.toString();
		System.out.println(aaa);
	}

	@After
	public void after() throws IOException{
		randomAccessFile.close();
		channel.close();
	}

	/**
	 * //1、读取数据Buffer
		//2、转换模式
		//3、读取Buffer
		//4、清除Buffers
	 * @throws IOException
	 */
	@Test
	public void readTest() throws IOException{
		System.out.println(read());
	}

	private String read() throws IOException {
		StringBuilder builder=new StringBuilder();
		int readByte=channel.read(buffer);
		while(readByte!=-1){
			//1、读取数据Buffer
			//2、转换模式
			buffer.flip();
			//3、读取Buffer
			byte[] datas=new byte[buffer.limit()];
			buffer.get(datas);
			//System.out.println(new String(datas));
			builder.append(new String(datas));
			//4、清除Buffer
			buffer.clear();
		 readByte=channel.read(buffer);
		}
		 String aa=builder.toString();
		 return aa;
	}

	/**
	 * 将读出的文件内容回写到文件中
	 * 从文件的开始地方写入
	 * @throws IOException
	 */
	@Test
	public void writeTest() {
		try {

		//获取原有字符串
		String originString=read();
		//写入到buffer
		buffer.put(originString.getBytes());
		//转换模式
		buffer.flip();
		//将buffer中的数据写入到文件中
		channel.position(0);
		System.out.println("size:"+channel.size()+"\t"+"position:"+channel.position());
		@SuppressWarnings("resource")
		RandomAccessFile randomAccessFile2=new RandomAccessFile("/home/lhy/data/aaaa.txt", "rw");

		FileChannel channel2=randomAccessFile2.getChannel();
		while(buffer.hasRemaining())
		{
			channel2.write(buffer);
			System.out.println("0000000000000000");
		}

		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("11111111111111111111111");

	}

	//@Test
	public void writeAsyncTest() throws IOException, URISyntaxException{
		//获取原有字符串
	String originString=read();
	originString+=System.currentTimeMillis();
	//写入到buffer
	buffer.put(originString.getBytes());
	//转换模式
	buffer.flip();
	//Path file=Paths.get(ClassLoader.getSystemResource("selector1.txt").toURI());
	Path file=Paths.get("/home/lhy/data/aaaa.txt");
	fileChannel=AsynchronousFileChannel.open(file, StandardOpenOption.WRITE);
	fileChannel.force(true);
	//fileChannel.write(buffer, 10);
	fileChannel.write(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {

		@Override
		public void completed(Integer result, ByteBuffer attachment) {
			// TODO Auto-generated method stub
			System.out.println("写完文件后操作,不阻塞,已经写了"+result);
			close();
		}

		@Override
		public void failed(Throwable exc, ByteBuffer attachment) {
			// TODO Auto-generated method stub
			System.out.println("写失败");
			exc.printStackTrace();
		}
	});

	System.out.println("000000000000000000000000000000000000000000000000000000");
	}
	public void close(){
		try {
			fileChannel.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

多路复用器  Selector

服务端

[java] view plain copy

  1. package com.undergrowth;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStreamReader;  
  6. import java.net.InetSocketAddress;  
  7. import java.net.Socket;  
  8. import java.nio.channels.SelectionKey;  
  9. import java.nio.channels.Selector;  
  10. import java.nio.channels.ServerSocketChannel;  
  11. import java.util.Iterator;  
  12. import java.util.Set;  
  13.   
  14. import org.junit.After;  
  15. import org.junit.Before;  
  16. import org.junit.Test;  
  17.   
  18. /** 
  19.  * 测试多路复用器 Selector 
  20.  * @author u1 
  21.  * 
  22.  */  
  23. public class BasicSelector {  
  24.       
  25.     //多路复用器  检测7777和8888端口  
  26.     private Selector selector;  
  27.     private ServerSocketChannel channel7777,channel8888;  
  28.       
  29.     @Before  
  30.     public void before() throws IOException{  
  31.         selector=Selector.open();  
  32.         //打开7777端口服务通道  
  33.         channel7777=ServerSocketChannel.open();  
  34.         //绑定7777端口的服务监听  
  35.         channel7777.socket().bind(new InetSocketAddress(7777));  
  36.         //配置为非阻塞模式  
  37.         channel7777.configureBlocking(false);  
  38.         //将通道注册到多路复用器上  
  39.         channel7777.register(selector,  SelectionKey.OP_ACCEPT);  
  40.         //打开8888端口服务通道  
  41.         channel8888=ServerSocketChannel.open();  
  42.         //绑定8888端口的服务监听  
  43.         channel8888.socket().bind(new InetSocketAddress(9999));  
  44.         //配置为非阻塞模式  
  45.         channel8888.configureBlocking(false);  
  46.         //关注读操作  
  47.         channel8888.register(selector, SelectionKey.OP_ACCEPT);  
  48.     }  
  49.       
  50.     /** 
  51.      * 关闭资源 
  52.      * @throws IOException 
  53.      */  
  54.     @After  
  55.     public void after() throws IOException{  
  56.         selector.close();  
  57.         channel7777.close();  
  58.         channel8888.close();  
  59.     }  
  60.       
  61.     @Test  
  62.     public void select() throws IOException{  
  63.         //控制循环  
  64.         BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));  
  65.         while(true){  
  66.             System.out.println("是否还要进行");  
  67.             String isGoString=reader.readLine();  
  68.             if("N".equalsIgnoreCase(isGoString)) break;  
  69.             System.out.println("等待事件源发生");  
  70.             //等待注册的事件源发生  
  71.             int readyChannel=selector.select();  
  72.             if(readyChannel==0) continue;  
  73.             System.out.println("有"+readyChannel+"个准备好了");  
  74.             //获取准备好的通道  
  75.             Set<SelectionKey> selectionKeys=selector.selectedKeys();  
  76.             Iterator<SelectionKey> selectKeyIterator=selectionKeys.iterator();  
  77.             while (selectKeyIterator.hasNext()) {  
  78.                 SelectionKey selectionKey = (SelectionKey) selectKeyIterator  
  79.                         .next();  
  80.                 //遍历注册中准备好的事件源  
  81.                 interestSet(selectionKey.interestOps());  
  82.                 if(selectionKey.isAcceptable()){  
  83.                     //当客户端进行连接时  获取socket  会写信息  
  84.                     ServerSocketChannel serverSocketChannel=(ServerSocketChannel) selectionKey.channel();  
  85.                     System.out.println(serverSocketChannel.socket().getLocalPort()+"端口\t"+"感兴趣的操作:"+serverSocketChannel.validOps());  
  86.                     Socket socket=serverSocketChannel.socket().accept();  
  87.                     socket.getOutputStream().write("从selector中返回给客户端".getBytes());  
  88.                     socket.getOutputStream().flush();  
  89.                     socket.close();  
  90.                 }  
  91.                 //移除已经处理的事件源  
  92.                 selectKeyIterator.remove();  
  93.             }  
  94.         }  
  95.           
  96.           
  97.     }  
  98.   
  99.     /** 
  100.      * 遍历注册中准备好的事件源 
  101.      * @param interestOps 
  102.      */  
  103.     private void interestSet(int interestSet) {  
  104.         // TODO Auto-generated method stub  
  105.         if((interestSet&SelectionKey.OP_ACCEPT)!=0) System.out.println("注册的可接受");  
  106.         if((interestSet&SelectionKey.OP_CONNECT)!=0) System.out.println("注册的可连接");  
  107.         if((interestSet&SelectionKey.OP_READ)!=0) System.out.println("注册的可读");  
  108.         if((interestSet&SelectionKey.OP_WRITE)!=0) System.out.println("注册的可写");  
  109.     }  
  110.       
  111.       
  112. }  

客户端

[java] view plain copy

  1. package com.undergrowth;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStreamReader;  
  6. import java.net.InetSocketAddress;  
  7. import java.net.Socket;  
  8.   
  9.   
  10. /** 
  11.  * 连接服务ServerSocket 
  12.  * @author u1 
  13.  * 
  14.  */  
  15. public class BasicSocketChannel {  
  16.   
  17.     /** 
  18.      * @param args 
  19.      * @throws IOException  
  20.      */  
  21.     public static void main(String[] args) throws IOException {  
  22.         // TODO Auto-generated method stub  
  23.           
  24.         //用于客户端的Socket连接 测试  
  25.         Socket socket=new Socket();  
  26.         socket.connect(new InetSocketAddress(7777));  
  27.         BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));   
  28.         System.out.println("读取的字符串为:"+reader.readLine());  
  29.           
  30.     }  
  31.   
  32. }  

路径   Path与Paths

[java] view plain copy

  1. package com.undergrowth;  
  2.   
  3. import java.nio.file.Path;  
  4. import java.nio.file.Paths;  
  5.   
  6. import org.junit.Test;  
  7.   
  8. /** 
  9.  * A Java Path instance represents a path in the file system. A path can point 
  10.  * to either a file or a directory. A path can be absolute or relative. An 
  11.  * absolute path contains the full path from the root of the file system down to 
  12.  * the file or directory it points to. A relative path contains the path to the 
  13.  * file or directory relative to some other path. 
  14.  *  
  15.  * @author u1 
  16.  *  
  17.  */  
  18. public class BasicPath {  
  19.   
  20.     /** 
  21.      * 测试绝对路径 
  22.      */  
  23.     @Test  
  24.     public void testAbsolute() {  
  25.         Path path=Paths.get("E:\\book", "JAVA_API_1.7中文.chm");  
  26.         System.out.println(path.toString());  
  27.     }  
  28.   
  29.     /** 
  30.      * 测试相对路径 
  31.      * .---->当前路径 
  32.      * ..---->父路径 
  33.      */  
  34.     @Test  
  35.     public void testRelative(){  
  36.         Path path=Paths.get(".");  
  37.         System.out.println(path.toAbsolutePath());  
  38.         path=Paths.get("..");  
  39.         System.out.println(path.toAbsolutePath());  
  40.     }  
  41.       
  42.     /** 
  43.      * 格式化Path路径  
  44.      * 去除.和.. 
  45.      */  
  46.     @Test  
  47.     public void testNormalize(){  
  48.         Path path=Paths.get("E:\\book\\weblogic\\.\\51CTO下载-Oracle WebLogic Server开发权威指南.part1.rar");  
  49.         System.out.println(path.toAbsolutePath());  
  50.         System.out.println(path.normalize().toAbsolutePath());  
  51.         path=Paths.get("E:\\book\\..\\");  
  52.         System.out.println(path.toAbsolutePath());  
  53.         System.out.println(path.normalize().toAbsolutePath());  
  54.     }  
  55.       
  56. }  

管道  Pipe

[java] view plain copy

  1. package com.undergrowth;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.ByteBuffer;  
  5. import java.nio.channels.Pipe;  
  6.   
  7. import org.junit.Before;  
  8. import org.junit.Test;  
  9.   
  10. /** 
  11.  * 管道操作 
  12.  *  
  13.  * A Java NIO Pipe is a one-way data connection between two threads. A Pipe has 
  14.  * a source channel and a sink channel. You write data to the sink channel. This 
  15.  * data can then be read from the source channel 
  16.  *  
  17.  * @author u1 
  18.  *  
  19.  */  
  20. public class BasicPipe {  
  21.   
  22.     Pipe pipe;  
  23.     Pipe.SinkChannel writePipe;  
  24.     Pipe.SourceChannel readPipe;  
  25.     ByteBuffer buffer;  
  26.       
  27.     @Before  
  28.     public void before() throws IOException{  
  29.         pipe=Pipe.open();  
  30.         writePipe=pipe.sink();  
  31.         readPipe=pipe.source();  
  32.         buffer=ByteBuffer.allocate(1024);  
  33.     }  
  34.       
  35.     @Test  
  36.     public void testPipe() throws IOException{  
  37.         String string="通过管道进行传输数据";  
  38.         buffer.put(string.getBytes());  
  39.         buffer.flip();  
  40.         //将数据写入接受的通道中  
  41.         while(buffer.hasRemaining()) writePipe.write(buffer);  
  42.         //将数据从读的通道中读出  
  43.         ByteBuffer byteBuffer=ByteBuffer.allocate(1024);  
  44.         StringBuilder builder=new StringBuilder();  
  45.         int readByte=readPipe.read(byteBuffer);  
  46.         byteBuffer.flip();  
  47.         byte[] dst=new byte[byteBuffer.limit()];  
  48.         byteBuffer.get(dst);  
  49.         builder.append(new String(dst));  
  50.         byteBuffer.clear();  
  51.         System.out.println("从读的通道中读出的数据为:"+builder.toString());  
  52.     }  
  53. }  

文件  Files

[java] view plain copy

  1. package com.undergrowth;  
  2.   
  3. import static org.junit.Assert.*;  
  4.   
  5. import java.io.IOException;  
  6. import java.nio.file.FileVisitResult;  
  7. import java.nio.file.FileVisitor;  
  8. import java.nio.file.Files;  
  9. import java.nio.file.LinkOption;  
  10. import java.nio.file.Path;  
  11. import java.nio.file.Paths;  
  12. import java.nio.file.SimpleFileVisitor;  
  13. import java.nio.file.StandardCopyOption;  
  14. import java.nio.file.attribute.BasicFileAttributes;  
  15.   
  16. import org.junit.Test;  
  17.   
  18. /** 
  19.  * The Java NIO Files class (java.nio.file.Files) provides several methods for 
  20.  * manipulating files in the file system. 
  21.  * 文件操作类 
  22.  *    新建两个文件夹 再将文件复制到两文件夹中 然后进行遍历文件树 遍历完成后 删除文件夹及文件 
  23.  * @author u1 
  24.  *  
  25.  */  
  26. public class BasicFiles {  
  27.   
  28.     @Test  
  29.     public void test() throws IOException {  
  30.         //获取路径  
  31.         Path path=Paths.get(".\\test");  
  32.         //分别创建两个文件夹 在test里面 分别为test1 和  test2  
  33.         createDir(path);  
  34.         //复制文件  
  35.         copyFiles(path);  
  36.         //遍历文件  
  37.         path=Paths.get(".\\test");  
  38.         walkFile(path);  
  39.     }  
  40.   
  41.     /** 
  42.      * 遍历文件目录 
  43.      * @param path 
  44.      * @throws IOException  
  45.      */  
  46.     private void walkFile(Path path) throws IOException {  
  47.         // TODO Auto-generated method stub  
  48.         Files.walkFileTree(path, new SimpleFileVisitor<Path>(){  
  49.   
  50.             @Override  
  51.             public FileVisitResult visitFile(Path file,  
  52.                     BasicFileAttributes attrs) throws IOException {  
  53.                 // TODO Auto-generated method stub  
  54.                 //删除文件  
  55.                 System.out.println("删除"+file.toFile().getAbsolutePath());  
  56.                 Files.delete(file);  
  57.                 return FileVisitResult.CONTINUE;  
  58.             }  
  59.   
  60.             @Override  
  61.             public FileVisitResult postVisitDirectory(Path dir, IOException exc)  
  62.                     throws IOException {  
  63.                 // TODO Auto-generated method stub  
  64.                 //遍历完目录后删除  
  65.                 System.out.println("遍历完目录后删除"+dir.toAbsolutePath());  
  66.                 Files.delete(dir);  
  67.                 return FileVisitResult.CONTINUE;  
  68.             }  
  69.               
  70.         });  
  71.     }  
  72.   
  73.     /** 
  74.      * 复制文件 
  75.      * @param path 
  76.      * @throws IOException  
  77.      */  
  78.     private void copyFiles(Path path) throws IOException {  
  79.         // TODO Auto-generated method stub  
  80.         Path pathSource =Paths.get("..\\git.txt");  
  81.         path=Paths.get(".\\test\\test1\\git.txt");  
  82.         //替换已经存在的文件  
  83.         Files.copy(pathSource, path,StandardCopyOption.REPLACE_EXISTING);  
  84.         path=Paths.get(".\\test\\test2\\git.txt");  
  85.         Files.copy(pathSource, path,StandardCopyOption.REPLACE_EXISTING);  
  86.     }  
  87.   
  88.     /** 
  89.      * 创建文件夹 
  90.      * @param path 
  91.      * @throws IOException 
  92.      */  
  93.     private void createDir(Path path) throws IOException {  
  94.         // TODO Auto-generated method stub  
  95.         if(!Files.exists(path, new LinkOption[]{LinkOption.NOFOLLOW_LINKS}))  
  96.             Files.createDirectories(path);  
  97.         path=Paths.get(path.toString(), "test1");  
  98.         if(!Files.exists(path, new LinkOption[]{LinkOption.NOFOLLOW_LINKS}))  
  99.             Files.createDirectories(path);  
  100.         path=Paths.get(path.toString(), "..\\test2");  
  101.         if(!Files.exists(path, new LinkOption[]{LinkOption.NOFOLLOW_LINKS}))  
  102.             Files.createDirectories(path);  
  103.     }  
  104.   
  105.       
  106. }  
时间: 2025-01-11 12:26:29

java nio 异步操作 (一)的相关文章

java Nio 异步操作(四)channel

Java NIO 的核心组成部分: 1.Channels 2.Buffers 3.Selectors 我们首先来学习Channels(java.nio.channels): 通道 1)通道基础 通道(Channel)是java.nio的第二个主要创新.它们既不是一个扩展也不是一项增强,而是全新.极好的Java I/O示例,提供与I/O服务的直接连接.Channel用于在字节缓冲区和位于通道另一侧的实体(通常是一个文件或套接字)之间有效地传输数据. channel的jdk源码: 1 2 3 4 5

java Nio 异步操作(三)

异步channel API 主要引入三个异步类: AsynchronousFileChannel,AsynchronousSocketChannel, and AsynchronousServerSocketChannel. AsynchronousFileChannel跟FileChannel区别:不保存全局的position和offset,可以制定访问位置,也支持并发访问文件不同. AsynchronousServerSocketChannel AsynchronousSocketChann

Java NIO API详解

详解 在JDK 1.4以前,Java的IO操作集中在java.io这个包中,是基于流的同步(blocking)API.对于大多数应用来说,这样的API使用很方便,然而,一些对性能要求较高的应用,尤其是服务端应用,往往需要一个更为有效的方式来处理IO.从JDK 1.4起,NIO API作为一个基于缓冲区,并能提供异步(non-blocking)IO操作的API被引入.本文对其进行深入的介绍. NIO API主要集中在java.nio和它的subpackages中: java.nio 定义了Buff

理解Java NIO

基础概念 • 缓冲区操作 缓冲区及操作是所有I/O的基础,进程执行I/O操作,归结起来就是向操作系统发出请求,让它要么把缓冲区里的数据排干(写),要么把缓冲区填满(读).如下图 • 内核空间.用户空间  上图简单描述了数据从磁盘到用户进程的内存区域移动的过程,其间涉及到了内核空间与用户空间.这两个空间有什么区别呢?  用户空间就是常规进程(如JVM)所在区域,用户空间是非特权区域,如不能直接访问硬件设备.内核空间是操作系统所在区域,那肯定是有特权啦,如能与设备控制器通讯,控制用户区域的进程运行状

攻破JAVA NIO技术壁垒

现在使用NIO的场景越来越多,很多网上的技术框架或多或少的使用NIO技术,譬如Tomcat,Jetty.学习和掌握NIO技术已经不是一个JAVA攻城狮的加分技能,而是一个必备技能.再者,现在互联网的面试中上点level的都会涉及一下NIO或者AIO的问题(AIO下次再讲述,本篇主要讲述NIO),掌握好NIO也能帮助你获得一份较好的offer. 驱使博主写这篇文章的关键是网上关于NIO的文章并不是很多,而且案例较少,针对这个特性,本文主要通过实际案例主要讲述NIO的用法,每个案例都经过实际检验.博

Java NIO Chapter1 Learning Tips

1.java.io效率低的原因But in most cases, Java applications have not truly been I/O bound in the sense that the operating system couldn't shuttle data fast enough to keep them busy. Instead, the JVMs have not been doing I/O efficiently. There's an impedance

JAVA NIO存在的问题

    JAVA 包含最新的版本JDK1.8的NIO存在一些问题,这些问题需要在编写NIO程序时要格外关注: NIO跨平台和兼容性问题     NIO是底层API,它的实现依赖于操作系统针对IO操作的APIs. 所以JAVA能在所有操作系统上实现统一的接口,并用一致的行为来操作IO是很伟大的.     使用NIO会经常发现代码在Linux上正常运行,但在Windows上就会出现问题.所以编写程序,特别是NIO程序,需要在程序支持的所有操作系统上进行功能测试,否则你可能会碰到一些莫明的问题.   

介绍一些 Java NIO 的学习文章,以方便各位的学习!

NIO 入门: http://www-900.ibm.com/developerWorks/cn/cnonlinetutorial.nsf/gethtml?OpenAgent&url=/developerWorks/cn/education/java/j-nio/tutorial/index.html Java NIO原理和使用 : http://www.jdon.com/concurrent/nio%D4%AD%C0%ED%D3%A6%D3%C3.htm Merlin 给 Java 平台带来了

基于java nio的memcached客户端

1.xmemcached是什么? xmemcached是基于java nio实现的memcached客户端API. 实际上是基于我实现的一个简单nio框架 http://code.google.com/p/yanf4j/的基础上实现的(目前是基于yanf4j 0.52),核心代码不超过1000行,序列化机制直接挪用spymemcached的Transcoder. 性能方面,在读写简单类型上比之spymemcached还是有差距,在读写比较大的对象(如集合)有效率优势. 当前0.50-beta版本