java nio 常见的nio类, nio 写文件方法, nio 比io 的优势
2016-06-24 16:12
435 查看
1..nio是同步非阻塞的意思, 以前的IO 都是阻塞IO, nio是非阻塞IO
2..阻塞非阻塞意思就是, 阻塞是线程一直等, 非阻塞是线程不等. 非阻塞就是来连接我不创建线程, 直到你来IO数据的请求, 即http 包, 我才创建线程, 如代码aaa处
int n = selector.select( ) 就是同步非阻塞的意思 , n代表IO请求的数量, 你来请求之前,我可以做我的事, 不是阻塞等, 你来请求之后即n>0, 我也照样可以做自己的事,
爱什么时候处理IO就什么时候处理IO 即非阻塞就是你来IO我才创建线程去处理
nio 代码如下:
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(); } }
相关文章推荐
- Java正则获取邮箱
- eclipse最有用快捷键整理
- Elasticsearch java API (5)Transport Client
- java编程心得(持续更新)
- java自学之旅(3)测试RandomAccessFile常用方法
- 华为机试---最大间隔
- java.util.concurrent
- Elasticsearch java API (4)部署在JBoss EAP6模块
- SpringMVC+Shiro权限管理
- Java NIO Channel
- Java正则抓取Email
- 玩转Eclipse开发工具(三)
- java创建二维码
- javaWeb程序的web.xml的作用
- eclipse启动出现“An Error has Occurred. See the log file”解决方法
- 【风马一族_Java】如何使用ACSLL表的值,
- Java_GC详解
- 整合springMVC+mybatis
- Java单线程连接SQL server2012数据库[JDBC驱动]
- Elasticsearch java API (3)