java nio 常见的nio类, nio 写文件方法, nio 比io 的优势

1..nio是同步非阻塞的意思, 以前的IO 都是阻塞IO, nio是非阻塞IO

2..阻塞非阻塞意思就是,  阻塞是线程一直等,  非阻塞是线程不等.   非阻塞就是来连接我不创建线程, 直到你来IO数据的请求, 即http 包, 我才创建线程, 如代码aaa处  

    int n = selector.select( ) 就是同步非阻塞的意思 , n代表IO请求的数量, 你来请求之前,我可以做我的事, 不是阻塞等, 你来请求之后即n>0, 我也照样可以做自己的事,

    爱什么时候处理IO就什么时候处理IO     即非阻塞就是你来IO我才创建线程去处理

nio 代码如下:

package NIO;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.FileChannel;
import java.nio.channels.Pipe;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Date;
import java.util.Iterator;
/**
 * 
 * NIO (2) Chanel,chanel 就是通道,ByteBuffer俗称缓冲器,ByteBuffer 底层用byte[]数组存储实现的
 * 以下函数注释中括号的数字对应如下链接中的章节,参考:http://ifeve.com/file-channel/
 * 
 * NIO 和IO 的区别:
 * nio 快,io 慢.(13)unBlockReadTest()函数
 * nio 不阻塞, io阻塞, 未看出
 * nio 可以从文件的指定位置读/写, io做不到  (14)updateFile()函数
 * 
 * @author jaloli
 * 
 */

public class FileChanelTest {
	//(2,3)
	public static void writeAndReadChanel() throws IOException {  //write buffer,read buffer
		RandomAccessFile aFile = new RandomAccessFile("nio-data.txt", "rw");
		FileChannel inChannel = aFile.getChannel();
		ByteBuffer buf = ByteBuffer.allocate(48);
		int bytesRead = inChannel.read(buf);
		while (bytesRead != -1) {
			System.out.println("Read " + bytesRead);
			buf.flip();//翻转缓冲,使其由能写变成能读
			System.out.println("初始 position :" +buf.position() + " limit : " + buf.limit() );
			while(buf.hasRemaining()){
				System.out.print( buf.position() + ":" + (char) buf.get() + " ");
			}
			buf.clear();
			bytesRead = inChannel.read(buf);
			System.out.println("\nRead " + bytesRead);
		}
		aFile.close();
	}
	//(4)分散(scatter)从Channel中读取是指在读操作时将读取的数据写入多个buffer中
	//聚集(gather)写入Channel是指在写操作时将多个buffer的数据写入同一个Channel
	public static void writeFileChanel() throws IOException {  //write chanel
		RandomAccessFile aFile = new RandomAccessFile("nio-data1.txt", "rw");
		FileChannel inChannel = aFile.getChannel();
		ByteBuffer body = ByteBuffer.allocate(6);
		ByteBuffer header = ByteBuffer.allocate(120000000);
		header.put(new byte[]{65,66,67,68,69,70});
		body.put(new byte[]{71,72,73,74,75,76});
		header.flip();
		body.flip();
//		System.out.println(header.getChar());
		ByteBuffer[] bufferArray = {header,body};//这里就是读buffer
		inChannel.write(bufferArray);
		aFile.close();
	}
	
	//(12)非阻塞测试, 如151行注释, 非block 并未发生,存疑
	public static void unBlockWriteTest() throws IOException {  //write chanel
		RandomAccessFile aFile = new RandomAccessFile("nio-data1.txt", "rw");
		FileChannel inChannel = aFile.getChannel();
		ByteBuffer body = ByteBuffer.allocate(6);
		ByteBuffer header = ByteBuffer.allocate(120000000);
		byte[] needWriteByte = new byte[10000000];
		byte[] needWriteByte1 = new byte[10000000];
		byte[] needWriteByte2 = new byte[10000000];
		byte[] needWriteByte3 = new byte[10000000];
		byte[] needWriteByte4 = new byte[10000000];
		byte[] needWriteByte5 = new byte[10000000];
		byte[] needWriteByte6 = new byte[10000000];
		byte[] needWriteByte7 = new byte[10000000];
		byte[] needWriteByte8 = new byte[10000000];
		byte[] needWriteByte9 = new byte[10000000];
		byte[] needWriteByte10 = new byte[10000000];
		byte[] needWriteByte11 = new byte[10000000];
		for(int i=0;i<10000000;i++){//10000000
			needWriteByte[i] = 1;
			needWriteByte1[i] = 1;
			needWriteByte2[i] = 1;
			needWriteByte3[i] = 1;
			needWriteByte4[i] = 1;
			needWriteByte5[i] = 1;
			needWriteByte6[i] = 1;
			needWriteByte7[i] = 1;
			needWriteByte8[i] = 1;
			needWriteByte9[i] = 1;
			needWriteByte10[i] = 1;
			needWriteByte11[i] = 1;
		}
		header.put(needWriteByte);
		header.put(needWriteByte1);
		header.put(needWriteByte2);
		header.put(needWriteByte3);
		header.put(needWriteByte4);
		header.put(needWriteByte5);
		header.put(needWriteByte6);
		header.put(needWriteByte7);
		header.put(needWriteByte8);
		header.put(needWriteByte9);
		header.put(needWriteByte10);
		header.put(needWriteByte11);
		body.put(new byte[]{71,72,73,74,75,76});//
		header.flip();
		body.flip();
		ByteBuffer[] bufferArray = {header,body};//   这里就是读buffer
		inChannel.write(bufferArray); //  这个会写117M的文件, 这个写的时候,卡住一下,写好后,再继续走下面的代码
		System.out.println("gggggggggggggggggggg");
		aFile.close();
	}
	
	//(13)nio 非阻塞读, 没看出来,但是看出来 nio 性能优于io
	public static void unBlockReadTest() throws IOException {  //write chanel
		RandomAccessFile aFile = new RandomAccessFile("nio-data1.txt", "rw");
		FileChannel inChannel = aFile.getChannel();
		int _5M = 1024*1024*5;
		ByteBuffer dst = ByteBuffer.allocateDirect(1);//_5M
		Date date = new Date();
		System.out.println(String.valueOf(date.getTime()));
		for(int i=0;i<10000000;i++){
			inChannel.read(dst);//这个就是一直在读文件的dst 个字节
//			inChannel.position(3);
//			System.out.println(inChannel.position());//以上两句有效,但是对read()方法无作用
//			System.out.println(byteBufferToString(dst));
		}
		System.out.println(String.valueOf(date.getTime()));//以上读完耗时忽略,是因为NIO面向的是data chunks,而java.io基本上是面向byte
		
		FileInputStream fr = new FileInputStream("nio-data1.txt");
		BufferedInputStream bis = new BufferedInputStream(fr);
		byte[] bytes = new byte[_5M];
		System.out.println(String.valueOf(date.getTime()));
		for(int i=0;i<10000000;i++) {
			System.out.println(bis.read(bytes));
		}
		System.out.println(String.valueOf(date.getTime()));//java io 读完耗时特别长,原因就是链接http://justjavac.iteye.com/blog/1998207 说的io 用吸管吸os给的一盆水 
	}
	
	//(14)nio 可以从文件指定位置写, 从文件指定位置读, io 做不到
	public static void updateFile() throws IOException {
		RandomAccessFile aFile = new RandomAccessFile("nio-data1.txt", "rw");
		FileChannel inChannel = aFile.getChannel();
		ByteBuffer needInsert = ByteBuffer.allocate(216);
		ByteBuffer readIn = ByteBuffer.allocate(216);
		needInsert.put("好".getBytes());
		needInsert.flip();//如果不加这句则无论字母汉字都是出乱码,因为后面的不可预知的字符会以utf-8等编码去解析
		inChannel.write(needInsert,3);//文件指定位置插入,源文件是 gegbbbbbbbbbwqfewq, 文件插入指定位置插入字符后变为  geg好bbbbbbbbbwqfewq
		inChannel.read(readIn, 3);//从指定位置读       我bbbbbbwqfewq
		readIn.flip();
		System.out.println(byteBufferToString(readIn));
		aFile.close();
	}
	
	//(5)transferFrom / transferTo
	public static void transferFromTest() {
		
	}
	
	//(6)selector 不懂干啥的,  浏览器中输入localhost:30/fdg 可以一直打印对象.代码参考:http://www.cnblogs.com/gaotianle/p/3325451.html
	public static void selectorTest() throws IOException {
		int port = 30;
		ServerSocketChannel serverChannel = ServerSocketChannel.open();
		ServerSocket serverSocket = serverChannel.socket();
		Selector selector = Selector.open();
		serverSocket.bind(new InetSocketAddress(port));
		serverChannel.configureBlocking(false);
		serverChannel.register(selector, SelectionKey.OP_ACCEPT);// 第二个参数是四种事件。这样serverChannel
																	// 作为一个channel
																	// 就注册到selector
																	// 上了
		while (true) {//<strong>selector 负责监听channel上有无数据,监听到后,channel 去read()拿数据</strong>
			int n = selector.select();//这里就是同步非阻塞, 也就是nio同步非阻塞的意思所在aaa
			if (n == 0) {             //但是这里非阻塞虽然不用一直等IO请求, 但也在一直轮询, 所以比较耗费资源, 因此出现aio
				continue; // nothing to do,其实这里可以做别的事,即非阻塞, 做一定的事后, 可以再selector.select() 判断有无IO请求到来,而不是一来个连接,就创建线程等待IO.
			}
			Iterator it = selector.selectedKeys().iterator();
			while (it.hasNext()) {							//当然这里如果来了IO请求, 那么本例没创建线程,而是用当前线程去处理IO数据
				SelectionKey key = (SelectionKey) it.next();
				if (key.isAcceptable()) {
					ServerSocketChannel serverchanel = (ServerSocketChannel) key.channel();
					SocketChannel channel = serverchanel.accept();
					if (channel == null) {
						;// handle code, could happen
					}
					channel.configureBlocking(false);// selector.select
														// 来选择已经注册的多个通道之一
					channel.register(selector, SelectionKey.OP_READ);
				} else if (key.isReadable()) {
					SocketChannel channel = (SocketChannel) key.channel(); // 通过selector
																			// 的key
																			// 拿到channel
					ByteBuffer buffer = ByteBuffer.allocate(48);// channel
																// 的东西落到buffer
																// 里,进而转化成byte,转化成string
					int read = channel.read(buffer);
					byte[] data = buffer.array();
					String message = new String(data);
					System.out.println("接收到的消息是: " + message);
				} else if (key.isWritable()) {

				} else if (key.isConnectable()) {
					SelectableChannel chanel = key.channel();
					System.out.println(chanel.toString());
				}
				it.remove();
			}
		}
	}
	//ByteBuffer to String
	private static String byteBufferToString(ByteBuffer buf) {
		CharBuffer charBuffer = null;
		try{
			if(buf.position() != 0)
				buf.flip();   //flip() 函数是让  ByteBuffer 对象的position 变为0. 这里不flip()打不出来ByteBuffer 缓冲区的数据
			Charset charset = Charset.forName("UTF-8");
			CharsetDecoder decoder = charset.newDecoder();
			charBuffer = decoder.decode(buf);
			return charBuffer.toString();
		} catch(Exception ex) {
			ex.printStackTrace();
		}
		return null;
	}
	
	//(7)FileChannel
	public static void fileChannelTest() throws IOException{
		//FileChannel 读数据
		RandomAccessFile rFile = new RandomAccessFile("D:/xiecheng/EclipseWorkingspace/WorkspaceLearning/jsp_api/src/FileChannelReadTest.txt", "rw");
		FileChannel inChannel = rFile.getChannel();
		ByteBuffer buf = ByteBuffer.allocate(48);
		int bytesRead = inChannel.read(buf);
		String readFileContent = byteBufferToString(buf);
		System.out.println("读文件结果为: "+readFileContent);
		
		//FileChannel 写数据
		RandomAccessFile wFile = new RandomAccessFile("D:/xiecheng/EclipseWorkingspace/WorkspaceLearning/jsp_api/src/FileChannelWriteTest.txt", "rw");
		FileChannel outChannel = wFile.getChannel();
		String needWrite = "我被写入文件aaa";
		ByteBuffer needWriteBuf = ByteBuffer.allocate(48); 
		needWriteBuf.clear();
		needWriteBuf.put(needWrite.getBytes());
		needWriteBuf.flip();
		while(needWriteBuf.hasRemaining()) {
			outChannel.write(needWriteBuf);
		}
		System.out.println("写文件结果请看文件本身,写的内容是:"+needWrite);
	}
	
	//(8)SocketChannel如上面(6)  
	
	//(10)DatagramChannel实现UDP传输,使用如下两个函数,  参考http://www.cnblogs.com/bronte/articles/1966607.html
	public static void socketChannelServerTest() throws IOException{
		DatagramChannel channel = DatagramChannel.open();
		channel.socket().bind(new InetSocketAddress(9991));
		ByteBuffer buf = ByteBuffer.allocate(48);
		buf.clear();
		channel.receive(buf);
		String readFileContent = byteBufferToString(buf);
		System.out.println("SocketChannel 接收的结果为: "+readFileContent);
	}
	//这个客户端函数在另一个类中运行,方便查看客户端给服务端发的数据
	public static void socketChannelClientTest() throws IOException{
		DatagramChannel channel = DatagramChannel.open();
		String newData = "New String to write to file..." + System.currentTimeMillis();
		ByteBuffer buf = ByteBuffer.allocate(48);
		buf.clear();
		buf.put(newData.getBytes());
		buf.flip();
		int bytesSent = channel.send(buf, new InetSocketAddress(9991));

	}
	//(11)Pipe
	public static void pipeTest() throws IOException {
		//写
		Pipe pipe = Pipe.open();
		Pipe.SinkChannel sinkChannel = pipe.sink();
		String newData = "New String to write to file..." + System.currentTimeMillis();
		ByteBuffer needBeWriteBuf = ByteBuffer.allocate(48);//此时needBeWriteBuf 这个ByteBuffer 的limit 值是0
		needBeWriteBuf.clear();
		needBeWriteBuf.put(newData.getBytes());
		System.out.println("needBeWriteBuf 的postion 和 limit 分别是: "+needBeWriteBuf.position() +", "+ needBeWriteBuf.limit());
		needBeWriteBuf.flip(); //position 设置为0,即顶头,读写公用一个position
		while(needBeWriteBuf.hasRemaining()) { //这个一次可能写0个到多个,所以需要重复写
			int byteWriteNum = sinkChannel.write(needBeWriteBuf);//write 之后,needBeWriteBuf 的position 就变成了43
			System.out.println("往sinkChannel 写的数据字节数为:" + byteWriteNum + ", 写的数据为: " + newData);
		}
		//读
		Pipe.SourceChannel sourceChannel = pipe.source();
		ByteBuffer needReadToBuf = ByteBuffer.allocate(48);
		int byteReadNum = sourceChannel.read(needReadToBuf);
		System.out.println("read 之后, postion is : "+needReadToBuf.position());  //read 一次, position 变为43
		String sourceChannelContent = byteBufferToString(needReadToBuf);
		System.out.println("sourceChannel 接收的结果长度为: " + byteReadNum +", sourceChannel 接收的结果为: "+sourceChannelContent);
	}
	
	//ByteBuffer 缓冲区
	public static void byteBufferTest(){
		ByteBuffer needBeWriteBuf = ByteBuffer.allocate(48);
		needBeWriteBuf.clear();
		needBeWriteBuf.put("我".getBytes());
		needBeWriteBuf.put("我".getBytes());
		needBeWriteBuf.put("我".getBytes());
//		needBeWriteBuf.clear(); //buffer.clear()  缓冲区清空了
		needBeWriteBuf.put("你".getBytes()); //正常追加到缓冲区, 我我我你
		
		String sourceChannelContent = byteBufferToString(needBeWriteBuf);
		System.out.println("ByteBuffer 缓冲区内容是  is " + sourceChannelContent);
	}
	
	public static void main(String[] args) throws IOException {
//		writeAndReadChanel();
//		writeFileChanel();
//		selectorTest();
//		fileChannelTest();
//		socketChannelServerTest();
//		pipeTest();
//		byteBufferTest();
//		unBlockWriteTest();
//		unBlockReadTest();
		updateFile();
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值