问题:如果一个程序现在需要等待用户输入数据,则可以通过 system.in 来完成。但是这样一来,在使用时就会出现一个问题:
如果用户没有输入信息,则肯定会一直等待用户输入,大量的系统资源就会被败白白浪费。所以在 jdk 1.4 之后引入了 新IO 处理机制。---NIO .
IO的阻塞操作:
我们知道 在IO操作中从键盘解说数据是我们会使用readLine()方法,程序就要停止等待用户输入数据;在网络编程中我们知道在服务器端使用ServletSocket 类的accept() 方法时,服务器会一直处于等待操作,等待客户端连接。这两类操作都属于阻塞操作,因为都会让程序暂停。
新IO并没有在原来的IO基础上开发,而是采用了全新的类和接口,除了原有的功能之外还提供了一下新的特性:
多路选择的非封锁式I/O设施;
支持文件锁和内存映射;
支持正则表达式的模式匹配设施;
字符集编码器和译码器。
在新IO中使用 Buffer 和Channel 支持以上的操作。
一、缓冲区与Buffer
1、基本操作:
在基本IO操作中所有的操作都是直接一流的形式完成的;而在NIO中所有的操作都要使用缓冲区处理,且所有的读写操作都是通过缓冲区完成的。缓冲区(Buffer)是一个线性的、有序的数据集,只能容纳某种特定的事数据类型。
java.nio.Buffer 本身是一个抽象类;
Buffer有四个基本属性:
1、capacity 容量,buffer能够容纳的最大元素数目,在Buffer创建时设定并不能更改
2、limit buffer中有效位置数目
3、position 下一个读或者写的位置
4、mark 用于记忆的标志位,配合reset()使用,初始值未设定,调用mark后将当前position设为值
四者关系:0 <= mark <= position <= limit <= capacity
API:
package java.nio;
public abstract class Buffer {
public final int capacity( )
public final int position( )
public final Buffer position (int newPosition)
public final int limit( )
public final Buffer limit (int newLimit)
public final Buffer mark( )
public final Buffer reset( )
public final Buffer clear( )
public final Buffer flip( )
public final Buffer rewind( )
public final int remaining( )
public final boolean hasRemaining( )
public abstract boolean isReadOnly( );
}
支持链式调用,如:buffer.mark().position(5).reset( );
注意isReadOnly()方法决定了buffer是否可写。
下面以IntBuffer类的操作为实例:
代码:
package com.zsc.day02; import java.nio.IntBuffer; public class IntBufferDemo { public static void main(String[] args) { //声明int类型缓冲区 ,开辟缓冲区大小为10 IntBuffer buf=IntBuffer.allocate(10); System.out.println("1.写入数据之前:position="+buf.position()+"," + "limit="+buf.limit()+",capacity="+buf.capacity()); int temp[]={2,3,4,8,3,4}; buf.put(1); //写入数据 buf.put(temp); System.out.println("2.写入数据之后:position="+buf.position()+"," + "limit="+buf.limit()+",capacity="+buf.capacity()); buf.flip(); // 重置缓冲区 即position=0,limit=原本position System.out.println("3.准备输出数据时:position="+buf.position()+"," + "limit="+buf.limit()+",capacity="+buf.capacity()); //输出缓冲去内容 while(buf.hasRemaining()){ int x=buf.get(); System.out.print(x+" "); } } }
1.写入数据之前:position=0,limit=10,capacity=10 2.写入数据之后:position=7,limit=10,capacity=10 3.准备输出数据时:position=0,limit=7,capacity=10 1 2 3 4 8 3 4
Exception in thread "main" java.nio.BufferOverflowException代码
package com.zsc.day02; import java.nio.IntBuffer; public class IntBufferDemo { public static void main(String[] args) { //声明int类型缓冲区 ,开辟缓冲区大小为5 IntBuffer buf=IntBuffer.allocate(5); System.out.println("1.写入数据之前:position="+buf.position()+"," + "limit="+buf.limit()+",capacity="+buf.capacity()); int temp[]={2,3,4,8,3,4}; buf.put(1); //写入数据 buf.put(temp); System.out.println("2.写入数据之后:position="+buf.position()+"," + "limit="+buf.limit()+",capacity="+buf.capacity()); buf.flip(); // 重置缓冲区 即position=0,limit=原本position System.out.println("3.准备输出数据时:position="+buf.position()+"," + "limit="+buf.limit()+",capacity="+buf.capacity()); //输出缓冲去内容 while(buf.hasRemaining()){ int x=buf.get(); System.out.print(x+" "); } } }运行结果
Exception in thread "main" java.nio.BufferOverflowException at java.nio.HeapIntBuffer.put(HeapIntBuffer.java:183) at java.nio.IntBuffer.put(IntBuffer.java:832) at com.zsc.day02.IntBufferDemo.main(IntBufferDemo.java:11)
package com.zsc.day02; import java.nio.IntBuffer; import java.nio.IntBuffer; public class IntBufferDemo02 { public static void main(String[] args) { IntBuffer buf=IntBuffer.allocate(10); //声明int类型缓冲区 开辟10个大小缓冲区 IntBuffer sub=null; //定义缓冲区对象 for(int i=0;i<10;i++){ buf.put(2*i+1); //加入10个奇数 } //创建子缓冲区 buf.position(2); //主缓冲区设置在第三个元素上 buf.limit(6); //主缓冲区limit 为6 sub=buf.slice(); //开辟子缓冲区 for(int i=0;i<sub.capacity();i++){ int temp=sub.get(i); //根据下表去的元素 sub.put(temp-1); //改变子缓冲区内容 } buf.flip();//重设缓冲区 buf.limit(buf.capacity()); //设置limit //输出缓冲区内容 while(buf.hasRemaining()){ //只要缓冲区中有数据则输出 int x=buf.get(); // 取出当前内容 System.out.print(x+" "); } } }
1 3 4 6 8 10 13 15 17 19
package com.zsc.day02; import java.nio.IntBuffer; import java.nio.IntBuffer; public class IntBufferDemo03 { public static void main(String[] args) { IntBuffer buf=IntBuffer.allocate(10); //声明int类型缓冲区 开辟10个大小缓冲区 IntBuffer readOnly=null; for(int i=0;i<10;i++){ buf.put(2*i+1); } //创建子缓冲区 buf.position(2); buf.limit(6); readOnly=buf.asReadOnlyBuffer(); readOnly.flip();//重设缓冲区 readOnly.limit(buf.capacity()); //输出缓冲区内容 while(readOnly.hasRemaining()){ int x=readOnly.get(); System.out.print(x+" "); } System.out.println(); // readOnly.put(30); //错误不可写 } }
1 3 5 7 9 11 13 15 17 19
package com.zsc.day02; import java.nio.ByteBuffer; public class ByteBufferDemo { public static void main(String[] args) { //声明ByteBuffer 对象 ByteBuffer buf = null ; //直接开辟缓冲区 buf = ByteBuffer. allocateDirect(10); byte temp[]={2,3,4,5,6,8,1}; //定义 byte数组 buf.put(temp); //向缓冲区中 写入一组数据 buf.flip(); //重设缓冲区 System.out.println("缓冲区中的内容:"); while(buf.hasRemaining()){ int x=buf.get(); System.out.print(x+" "); } } }
2 3 4 5 6 8 1
package com.zsc.day02; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class FileChannelTest { public static void main(String[] args) throws Exception { File f1 = new File("d:"+File.separator+"Hello.java"); File f2 = new File("d:"+File.separator+"outHello.java"); FileInputStream fis = null ;//文件输入流 FileOutputStream fos = null ;//文件输出流 fis = new FileInputStream(f1);//实例化输入流 fos = new FileOutputStream(f2);//实例化输出流 FileChannel fin = null ;//声明输入的通道对象 FileChannel fon = null ;//声明输出的通道对象 fin = fis.getChannel();//得到输入的文件通道 fon = fos.getChannel();//得到输出的文件通道 ByteBuffer buf = ByteBuffer.allocate(1024);//开辟缓冲 int temp = 0 ;//声明变量接收的内容 while((temp=fin.read(buf))!=-1){//如果没读到底 buf.flip();//重设缓冲区 fon.write(buf);//输出缓冲区 buf.clear();//清空缓冲区 } fin.close();//关闭输入流 fon.close();//关闭输出流 fis.close();//关闭输入通道 fos.close();//关闭输出通道 } }
package com.zsc.day02; import java.io.File; import java.io.FileInputStream; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; public class ChannelTest { public static void main(String[] args) throws Exception { File file = new File("d:"+File.separator+"Hello.java"); FileInputStream fis = null ; //文件输入流 fis = new FileInputStream(file); //实例化输入流 FileChannel fin = null ; //声明输入的通道对象 fin = fis.getChannel(); //得到输入文件通道 MappedByteBuffer mbb = null ; //声明文件的内存映射 //将文件映射到内存中 mbb = fin.map(FileChannel.MapMode.READ_ONLY, 0, file.length()); byte data[] = new byte[(int)file.length()]; //开辟字节数组,接收数据 int foot = 0 ; //定义下标 while(mbb.hasRemaining()){ //判断数否有数据 data[foot++] = mbb.get(); //取出数据 } System.out.println(new String(data)); //显示输入的数据 fis.close(); //关闭输入流 fin.close(); //关闭输入通道 } }
public calss Hello{ public static void mian(String args[]){ System.out.println("hello"); } }
package com.zsc.day02; import java.io.File; import java.io.FileOutputStream; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; public class FileLockTest { public static void main(String[] args) throws Exception { File file = new File("d:"+File.separator+"Hello.java"); FileOutputStream fos = null ; fos = new FileOutputStream(file,true); FileChannel fon = null ; fon = fos.getChannel(); FileLock fl = fon.tryLock(); if(fl != null){ System.out.println(file.getName()+"文件锁定30秒。"); Thread.sleep(30000); fl.release(); System.out.println(file.getName()+"文件解除锁定。"); } fos.close(); fon.close(); } }
Hello.java文件锁定30秒。 Hello.java文件解除锁定。
package com.zsc.day02; import java.nio.charset.Charset; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; public class GetAllCharset { public static void main(String[] args) { SortedMap<String,Charset> all = null ; //声明 SortedMap 集合 all = Charset.availableCharsets(); //获取全部编码 Iterator<Map.Entry<String,Charset>> iter = null ; //声明 Iterator 对象 iter = all.entrySet().iterator(); //实例化 Iterator while(iter.hasNext()){ //迭代输出 Map.Entry<String, Charset> me = iter.next(); //取出每一个Map.Entry System.out.println(me.getKey()+"---->"+me.getValue()); //输出信息 } } }
Big5---->Big5 Big5-HKSCS---->Big5-HKSCS EUC-JP---->EUC-JP EUC-KR---->EUC-KR GB18030---->GB18030 GB2312---->GB2312 GBK---->GBK IBM-Thai---->IBM-Thai IBM00858---->IBM00858 IBM01140---->IBM01140 IBM01141---->IBM01141 IBM01142---->IBM01142 ...
package com.zsc.day02; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; public class CharsetEnDeTest { public static void main(String[] args) throws Exception { Charset latin1 = Charset.forName("ISO-8859-1"); CharsetEncoder encoder = latin1.newEncoder(); CharsetDecoder decoder = latin1.newDecoder(); //通过CharBuffer 类中的 wrap()方法,将一个字符串变为CharBuffer 类型 CharBuffer cb = CharBuffer.wrap("圣诞快乐"); ByteBuffer buf = encoder.encode(cb); System.out.println(decoder.decode(buf)); } }
Exception in thread "main" java.nio.charset.UnmappableCharacterException: Input length = 1 at java.nio.charset.CoderResult.throwException(CoderResult.java:278) at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:798) at com.zsc.day02.CharsetEnDeTest.main(CharsetEnDeTest.java:17)
package com.zsc.day02; import java.net.InetSocketAddress; import java.net.ServerSocket; 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.Date; import java.util.Iterator; import java.util.Set; public class DateServer { public static void main(String[] args) throws Exception { //所有异常抛出 int ports[] = {8000,8001,8002,8003,8004,8005,8006,8007,8008}; //定义一组连接端口 Selector selector = Selector.open(); //打开一个选择器 for(int i = 0 ;i<ports.length;i++){ //构造服务器的启动消息 ServerSocketChannel initSer = null ; //声明CharSocketChannel initSer = ServerSocketChannel.open(); //打开服务器套接字通道 initSer.configureBlocking(false); //服务器配置为非阻塞 ServerSocket initSock = initSer.socket(); //检索与此通道关联的服务器套接字 InetSocketAddress address = null ; //表示监听地址 address = new InetSocketAddress(ports[i]); //实例化绑定地址 initSock.bind(address); //绑定地址 //注册选择器,相当于使用accept() 方法接收 initSer.register(selector, SelectionKey.OP_ACCEPT); // System.out.println("服务器运行,在"+ports[i]+"端口监听。"); // } int keysAdd = 0 ; // while((keysAdd=selector.select())>0){ //接收一组SelectionKey Set<SelectionKey> selectedKeys = selector.selectedKeys(); //选择一组键,相应的通道以为IO准备就绪 //取出全部生成的key Iterator<SelectionKey> iter = selectedKeys.iterator(); while(iter.hasNext()){ //迭代全部的key SelectionKey key = (SelectionKey)iter.next(); // if(key.isAcceptable()){ //取出每一个Selectionkey,判断客户端是否已经连接上 ServerSocketChannel server = (ServerSocketChannel)key.channel(); //取得 Channel SocketChannel client = server.accept(); //接收新连接 client.configureBlocking(false); //设置非阻塞状态 ByteBuffer outBuf = ByteBuffer.allocateDirect(1024); //开辟缓冲去 outBuf.put(("当前时间为:"+new Date()).getBytes()); //向缓冲区设置内容 outBuf.flip(); //重置缓冲区 client.write(outBuf); //输出信息 client.close(); //关闭输出流 } } selectedKeys.clear(); //清除全部的key } } }