NIO-缓存-通道-选择器

来源:互联网 发布:淘宝网店海报分辨率 编辑:程序博客网 时间:2024/06/07 06:32

NIO

1、通道

2、缓冲区 (间接内存-非直接缓冲区,直接内存--直接缓冲区)

3、阻塞通道示例

4、非阻塞通道示例 ----选择器(多路复用IO模型)

---主要是将 通道 和 selector·选择器 进行绑定,基于IO的多路复用模型,使用一个或多进行轮询注册通道,根据状态返回值进行操作

5、管道

6、Path、Paths、Files 类


1、通道

1NIO中的Channel的主要实现有:

FileChannel:用于读取、写入、映射和操作文件的通道。

DatagramChannel:通过UDP 读写网络中的数据通道。
SocketChannel:通过TCP 读写网络中的数据。
ServerSocketChannel:可以监听新进来的TCP 连接,对每一个新进来的连接都会创建一个SocketChannel。

这里看名字就可以猜出个所以然来:分别可以对应文件IOUDPTCPServerClient

 

2、获取通道的方式:

获取通道的一种方式是对支持通道的对象调用

getChannel() 方法。支持通道的类如下:

FileInputStream

FileOutputStream

RandomAccessFile

DatagramSocket

Socket

ServerSocket

获取通道的其他方式是使用Files 类的静态方法newByteChannel() 获取字节通道。或者通过通道的静态方法open() 打开并返回指定通道。


关键点:代码示例中有体现:

1、通道的分散和聚集Scatter/Gatter

分散(scatter)从Channel中读取是指在读操作时将读取的数据写入多个buffer中。因此,Channel将从Channel中读取的数据“分散(scatter)”到多个Buffer中。

聚集(gather)写入Channel是指在写操作时将多个buffer的数据写入同一个Channel,因此,Channel 将多个Buffer中的数据“聚集(gather)”后发送到Channel

scatter / gather经常用于需要将传输的数据分开处理的场合,例如传输一个由消息头和消息体组成的消息,你可能会将消息体和消息头分散到不同的buffer中,这样你可以方便的处理消息头和消息体。(应用场景)

注重提到的应用点,请求头+请求体 用不同的buffer传输

ther()    {        ByteBuffer header = ByteBuffer.allocate(10);        ByteBuffer body = ByteBuffer.allocate(10);        byte [] b1 = {'0', '1'};        byte [] b2 = {'2', '3'};        header.put(b1);        body.put(b2);        ByteBuffer [] buffs = {header, body};        try        {            FileOutputStream os = new FileOutputStream("src/scattingAndGather.txt");            FileChannel channel = os.getChannel();            channel.write(buffs);        }        catch (IOException e)        {            e.printStackTrace();        }    }}

2、 通道之间的数据传输(直接缓冲区) transferFrom() transferTo()   //示例代码中有体现


 代码示例:

/* * 一、通道(Channel):用于源节点与目标节点的连接。在 Java NIO 中负责缓冲区中数据的传输。Channel 本身不存储数据,因此需要配合缓冲区进行传输。 *  * 二、通道的主要实现类 * java.nio.channels.Channel 接口: * |--FileChannel * |--SocketChannel * |--ServerSocketChannel * |--DatagramChannel *  * 三、获取通道 * 1. Java 针对支持通道的类提供了 getChannel() 方法 * 本地 IO: * FileInputStream/FileOutputStream * RandomAccessFile *  * 网络IO: * Socket * ServerSocket * DatagramSocket *  * 2. 在 JDK 1.7 中的 NIO.2 针对各个通道提供了静态方法 open() * 3. 在 JDK 1.7 中的 NIO.2 的 Files 工具类的 newByteChannel() *  * 四、通道之间的数据传输 * transferFrom() * transferTo() *  * 五、分散(Scatter)与聚集(Gather) * 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中 * 聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中 *  * 六、字符集:Charset * 编码:字符串 -> 字节数组 * 解码:字节数组  -> 字符串 *  */public class TestChannel {//字符集@Testpublic void test6() throws IOException{Charset cs1 = Charset.forName("GBK");//获取编码器CharsetEncoder ce = cs1.newEncoder();//获取解码器CharsetDecoder cd = cs1.newDecoder();CharBuffer cBuf = CharBuffer.allocate(1024);cBuf.put("尚硅谷威武!");cBuf.flip();//编码ByteBuffer bBuf = ce.encode(cBuf);for (int i = 0; i < 12; i++) {System.out.println(bBuf.get());}//解码bBuf.flip();CharBuffer cBuf2 = cd.decode(bBuf);System.out.println(cBuf2.toString());System.out.println("------------------------------------------------------");Charset cs2 = Charset.forName("GBK");bBuf.flip();CharBuffer cBuf3 = cs2.decode(bBuf);System.out.println(cBuf3.toString());}@Testpublic void test5(){Map<String, Charset> map = Charset.availableCharsets();Set<Entry<String, Charset>> set = map.entrySet();for (Entry<String, Charset> entry : set) {System.out.println(entry.getKey() + "=" + entry.getValue());}}//分散和聚集@Testpublic void test4() throws IOException{RandomAccessFile raf1 = new RandomAccessFile("1.txt", "rw");//1. 获取通道FileChannel channel1 = raf1.getChannel();//2. 分配指定大小的缓冲区ByteBuffer buf1 = ByteBuffer.allocate(100);ByteBuffer buf2 = ByteBuffer.allocate(1024);//3. 分散读取ByteBuffer[] bufs = {buf1, buf2};channel1.read(bufs);for (ByteBuffer byteBuffer : bufs) {byteBuffer.flip();}System.out.println(new String(bufs[0].array(), 0, bufs[0].limit()));System.out.println("-----------------");System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));//4. 聚集写入RandomAccessFile raf2 = new RandomAccessFile("2.txt", "rw");FileChannel channel2 = raf2.getChannel();channel2.write(bufs);}//通道之间的数据传输(直接缓冲区)@Testpublic void test3() throws IOException{FileChannel inChannel = FileChannel.open(Paths.get("d:/1.mkv"), StandardOpenOption.READ);FileChannel outChannel = FileChannel.open(Paths.get("d:/2.mkv"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);//inChannel.transferTo(0, inChannel.size(), outChannel);outChannel.transferFrom(inChannel, 0, inChannel.size());inChannel.close();outChannel.close();}//使用直接缓冲区完成文件的复制(内存映射文件)@Testpublic void test2() throws IOException{//2127-1902-1777long start = System.currentTimeMillis();FileChannel inChannel = FileChannel.open(Paths.get("d:/1.mkv"), StandardOpenOption.READ);FileChannel outChannel = FileChannel.open(Paths.get("d:/2.mkv"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);//内存映射文件MappedByteBuffer inMappedBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());MappedByteBuffer outMappedBuf = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());//直接对缓冲区进行数据的读写操作byte[] dst = new byte[inMappedBuf.limit()];inMappedBuf.get(dst);outMappedBuf.put(dst);inChannel.close();outChannel.close();long end = System.currentTimeMillis();System.out.println("耗费时间为:" + (end - start));}//利用通道完成文件的复制(非直接缓冲区)@Testpublic void test1(){//10874-10953long start = System.currentTimeMillis();FileInputStream fis = null;FileOutputStream fos = null;//①获取通道FileChannel inChannel = null;FileChannel outChannel = null;try {fis = new FileInputStream("d:/1.mkv");fos = new FileOutputStream("d:/2.mkv");inChannel = fis.getChannel();outChannel = fos.getChannel();//②分配指定大小的缓冲区ByteBuffer buf = ByteBuffer.allocate(1024);//③将通道中的数据存入缓冲区中while(inChannel.read(buf) != -1){buf.flip(); //切换读取数据的模式//④将缓冲区中的数据写入通道中outChannel.write(buf);buf.clear(); //清空缓冲区}} catch (IOException e) {e.printStackTrace();} finally {if(outChannel != null){try {outChannel.close();} catch (IOException e) {e.printStackTrace();}}if(inChannel != null){try {inChannel.close();} catch (IOException e) {e.printStackTrace();}}if(fos != null){try {fos.close();} catch (IOException e) {e.printStackTrace();}}if(fis != null){try {fis.close();} catch (IOException e) {e.printStackTrace();}}}long end = System.currentTimeMillis();System.out.println("耗费时间为:" + (end - start));}}





2、缓冲区:

1、缓冲区中的四个核心属性:

 capacity : 容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。

 limit : 界限,表示缓冲区中可以操作数据的大小。(limit后数据不能进行读写)

 position : 位置,表示缓冲区中正在操作数据的位置。

 mark : 标记,表示记录当前 position的位置。可以通过reset()恢复到mark的位置

0  <=  mark (jdk java.nio.Buffer源码中默认为-1) <=  position  <=  limit  <=  capacity

 

2、直接缓冲区与非直接缓冲区:

 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中

 直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率

 

直接缓冲区开辟堆外内存(jvm的直接内存区域)MappedByteBuffer类相当于一个资源映射文件,

滤过堆内存空间,直接对堆外内存进行操作,提高效率。

NIO 的 Buffer 还提供了一个可以直接访问系统物理内存的类 DirectBuffer。DirectBuffer 继承自 ByteBuffer,但和普通的 ByteBuffer 不同。普通的 ByteBuffer 仍然在 JVM 堆上分配空间,其最大内存受到最大堆的限制,而 DirectBuffer 直接分配在物理内存上,并不占用堆空间。在对普通的 ByteBuffer 访问时,系统总是会使用一个“内核缓冲区”进行间接的操作。而 DirectrBuffer 所处的位置,相当于这个“内核缓冲区”。因此,使用 DirectBuffer 是一种更加接近系统底层的方法,所以,它的速度比普通的 ByteBuffer 更快。DirectBuffer 相对于 ByteBuffer 而言,读写访问速度快很多,但是创建和销毁 DirectrBuffer 的花费却比 ByteBuffer 高

      参考:http://blog.csdn.net/phil_code/article/details/69056086  理解


 代码示例:

/* * 一、缓冲区(Buffer):在 Java NIO 中负责数据的存取。缓冲区就是数组。用于存储不同数据类型的数据 *  * 根据数据类型不同(boolean 除外),提供了相应类型的缓冲区: * ByteBuffer * CharBuffer * ShortBuffer * IntBuffer * LongBuffer * FloatBuffer * DoubleBuffer *  * 上述缓冲区的管理方式几乎一致,通过 allocate() 获取缓冲区 *  * 二、缓冲区存取数据的两个核心方法: * put() : 存入数据到缓冲区中 * get() : 获取缓冲区中的数据 *  * 三、缓冲区中的四个核心属性: * capacity : 容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。 * limit : 界限,表示缓冲区中可以操作数据的大小。(limit 后数据不能进行读写) * position : 位置,表示缓冲区中正在操作数据的位置。 *  * mark : 标记,表示记录当前 position 的位置。可以通过 reset() 恢复到 mark 的位置 *  * 0 <= mark <= position <= limit <= capacity *  * 四、直接缓冲区与非直接缓冲区: * 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中 * 直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率 */public class TestBuffer {@Testpublic void test3(){//分配直接缓冲区ByteBuffer buf = ByteBuffer.allocateDirect(1024);System.out.println(buf.isDirect());}@Testpublic void test2(){String str = "abcde";ByteBuffer buf = ByteBuffer.allocate(1024);buf.put(str.getBytes());buf.flip();byte[] dst = new byte[buf.limit()];buf.get(dst, 0, 2);System.out.println(new String(dst, 0, 2));System.out.println(buf.position());//mark() : 标记buf.mark();buf.get(dst, 2, 2);System.out.println(new String(dst, 2, 2));System.out.println(buf.position());//reset() : 恢复到 mark 的位置buf.reset();System.out.println(buf.position());//判断缓冲区中是否还有剩余数据if(buf.hasRemaining()){//获取缓冲区中可以操作的数量System.out.println(buf.remaining());}}@Testpublic void test1(){String str = "abcde";//1. 分配一个指定大小的缓冲区ByteBuffer buf = ByteBuffer.allocate(1024);System.out.println("-----------------allocate()----------------");System.out.println(buf.position());System.out.println(buf.limit());System.out.println(buf.capacity());//2. 利用 put() 存入数据到缓冲区中buf.put(str.getBytes());System.out.println("-----------------put()----------------");System.out.println(buf.position());System.out.println(buf.limit());System.out.println(buf.capacity());//3. 切换读取数据模式buf.flip();System.out.println("-----------------flip()----------------");System.out.println(buf.position());System.out.println(buf.limit());System.out.println(buf.capacity());//4. 利用 get() 读取缓冲区中的数据byte[] dst = new byte[buf.limit()];buf.get(dst);System.out.println(new String(dst, 0, dst.length));System.out.println("-----------------get()----------------");System.out.println(buf.position());System.out.println(buf.limit());System.out.println(buf.capacity());//5. rewind() : 可重复读buf.rewind();System.out.println("-----------------rewind()----------------");System.out.println(buf.position());System.out.println(buf.limit());System.out.println(buf.capacity());//6. clear() : 清空缓冲区. 但是缓冲区中的数据依然存在,但是处于“被遗忘”状态buf.clear();System.out.println("-----------------clear()----------------");System.out.println(buf.position());System.out.println(buf.limit());System.out.println(buf.capacity());System.out.println((char)buf.get());}}
 

3、阻塞通道示例


/* * 一、使用 NIO 完成网络通信的三个核心: *  * 1. 通道(Channel):负责连接 *  *    java.nio.channels.Channel 接口: * |--SelectableChannel * |--SocketChannel * |--ServerSocketChannel * |--DatagramChannel *  * |--Pipe.SinkChannel * |--Pipe.SourceChannel *  * 2. 缓冲区(Buffer):负责数据的存取 *  * 3. 选择器(Selector):是 SelectableChannel 的多路复用器。用于监控 SelectableChannel 的 IO 状况 *  */public class TestBlockingNIO {//客户端@Testpublic void client() throws IOException{//1. 获取通道SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);//2. 分配指定大小的缓冲区ByteBuffer buf = ByteBuffer.allocate(1024);//3. 读取本地文件,并发送到服务端while(inChannel.read(buf) != -1){buf.flip();sChannel.write(buf);buf.clear();}//4. 关闭通道inChannel.close();sChannel.close();}//服务端@Testpublic void server() throws IOException{//1. 获取通道ServerSocketChannel ssChannel = ServerSocketChannel.open();FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);//2. 绑定连接ssChannel.bind(new InetSocketAddress(9898));//3. 获取客户端连接的通道SocketChannel sChannel = ssChannel.accept();//4. 分配指定大小的缓冲区ByteBuffer buf = ByteBuffer.allocate(1024);//5. 接收客户端的数据,并保存到本地while(sChannel.read(buf) != -1){buf.flip();outChannel.write(buf);buf.clear();}//6. 关闭通道sChannel.close();outChannel.close();ssChannel.close();}}

public class TestBlockingNIO2 {//客户端@Testpublic void client() throws IOException{SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);ByteBuffer buf = ByteBuffer.allocate(1024);while(inChannel.read(buf) != -1){buf.flip();sChannel.write(buf);buf.clear();}sChannel.shutdownOutput();   //通知服务器发送完毕//接收服务端的反馈int len = 0;while((len = sChannel.read(buf)) != -1){buf.flip();System.out.println(new String(buf.array(), 0, len));buf.clear();}inChannel.close();sChannel.close();}//服务端@Testpublic void server() throws IOException{ServerSocketChannel ssChannel = ServerSocketChannel.open();FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);ssChannel.bind(new InetSocketAddress(9898));SocketChannel sChannel = ssChannel.accept();ByteBuffer buf = ByteBuffer.allocate(1024);while(sChannel.read(buf) != -1){buf.flip();outChannel.write(buf);buf.clear();}//发送反馈给客户端buf.put("服务端接收数据成功".getBytes());buf.flip();sChannel.write(buf);sChannel.close();outChannel.close();ssChannel.close();}}


4、非阻塞通道示例 ----选择器(多路复用IO模型)

主要是将 通道 和 selector·选择器 进行绑定,基于IO的多路复用模型,使用一个或多进行轮询注册通道,根据状态返回值进行操作

/* * 一、使用 NIO 完成网络通信的三个核心: *  * 1. 通道(Channel):负责连接 *  *    java.nio.channels.Channel 接口: * |--SelectableChannel * |--SocketChannel * |--ServerSocketChannel * |--DatagramChannel *  * |--Pipe.SinkChannel * |--Pipe.SourceChannel *  * 2. 缓冲区(Buffer):负责数据的存取 *  * 3. 选择器(Selector):是 SelectableChannel 的多路复用器。用于监控 SelectableChannel 的 IO 状况 *  */public class TestNonBlockingNIO {//客户端@Testpublic void client() throws IOException{//1. 获取通道SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));//2. 切换非阻塞模式sChannel.configureBlocking(false);//3. 分配指定大小的缓冲区ByteBuffer buf = ByteBuffer.allocate(1024);//4. 发送数据给服务端Scanner scan = new Scanner(System.in);while(scan.hasNext()){String str = scan.next();buf.put((new Date().toString() + "\n" + str).getBytes());buf.flip();sChannel.write(buf);buf.clear();}//5. 关闭通道sChannel.close();}//服务端@Testpublic void server() throws IOException{//1. 获取通道ServerSocketChannel ssChannel = ServerSocketChannel.open();//2. 切换非阻塞模式ssChannel.configureBlocking(false);//3. 绑定连接ssChannel.bind(new InetSocketAddress(9898));//4. 获取选择器Selector selector = Selector.open();//5. 将通道注册到选择器上, 并且指定“监听接收事件”ssChannel.register(selector, SelectionKey.OP_ACCEPT);//6. 轮询式的获取选择器上已经“准备就绪”的事件while(selector.select() > 0){//7. 获取当前选择器中所有注册的“选择键(已就绪的监听事件)”Iterator<SelectionKey> it = selector.selectedKeys().iterator();while(it.hasNext()){//8. 获取准备“就绪”的是事件SelectionKey sk = it.next();//9. 判断具体是什么事件准备就绪if(sk.isAcceptable()){//10. 若“接收就绪”,获取客户端连接SocketChannel sChannel = ssChannel.accept();//11. 切换非阻塞模式sChannel.configureBlocking(false);//12. 将该通道注册到选择器上sChannel.register(selector, SelectionKey.OP_READ);}else if(sk.isReadable()){//13. 获取当前选择器上“读就绪”状态的通道SocketChannel sChannel = (SocketChannel) sk.channel();//14. 读取数据ByteBuffer buf = ByteBuffer.allocate(1024);int len = 0;while((len = sChannel.read(buf)) > 0 ){buf.flip();System.out.println(new String(buf.array(), 0, len));buf.clear();}}//15. 取消选择键 SelectionKeyit.remove();}}}}


 

public class TestNonBlockingNIO2 {@Testpublic void send() throws IOException{DatagramChannel dc = DatagramChannel.open();dc.configureBlocking(false);ByteBuffer buf = ByteBuffer.allocate(1024);Scanner scan = new Scanner(System.in);while(scan.hasNext()){String str = scan.next();buf.put((new Date().toString() + ":\n" + str).getBytes());buf.flip();dc.send(buf, new InetSocketAddress("127.0.0.1", 9898));buf.clear();}dc.close();}@Testpublic void receive() throws IOException{DatagramChannel dc = DatagramChannel.open();dc.configureBlocking(false);dc.bind(new InetSocketAddress(9898));Selector selector = Selector.open();dc.register(selector, SelectionKey.OP_READ);while(selector.select() > 0){Iterator<SelectionKey> it = selector.selectedKeys().iterator();while(it.hasNext()){SelectionKey sk = it.next();if(sk.isReadable()){ByteBuffer buf = ByteBuffer.allocate(1024);dc.receive(buf);buf.flip();System.out.println(new String(buf.array(), 0, buf.limit()));buf.clear();}}it.remove();}}}

 

 

public class ServerConnect{    private static final int BUF_SIZE=1024;    private static final int PORT = 8080;    private static final int TIMEOUT = 3000;    public static void main(String[] args)    {        selector();    }    public static void selector() {        Selector selector = null;        ServerSocketChannel ssc = null;        try{            selector = Selector.open();            ssc= ServerSocketChannel.open();            ssc.socket().bind(new InetSocketAddress(PORT));            ssc.configureBlocking(false);            ssc.register(selector, SelectionKey.OP_ACCEPT);            while(true){                if(selector.select(TIMEOUT) == 0){                    System.out.println("==");                    continue;                }                Iterator<SelectionKey> iter = selector.selectedKeys().iterator();                while(iter.hasNext()){                    SelectionKey key = iter.next();                    if(key.isAcceptable()){                        handleAccept(key);                    }                    if(key.isReadable()){                        handleRead(key);                    }                    if(key.isWritable() && key.isValid()){                        handleWrite(key);                    }                    if(key.isConnectable()){                        System.out.println("isConnectable = true");                    }                    iter.remove();                }            }        }catch(IOException e){            e.printStackTrace();        }finally{            try{                if(selector!=null){                    selector.close();                }                if(ssc!=null){                    ssc.close();                }            }catch(IOException e){                e.printStackTrace();            }        }    }    public static void handleAccept(SelectionKey key) throws IOException{        ServerSocketChannel ssChannel = (ServerSocketChannel)key.channel();        SocketChannel sc = ssChannel.accept();        sc.configureBlocking(false);        sc.register(key.selector(), SelectionKey.OP_READ,ByteBuffer.allocateDirect(BUF_SIZE));    }    public static void handleRead(SelectionKey key) throws IOException{        SocketChannel sc = (SocketChannel)key.channel();        ByteBuffer buf = (ByteBuffer)key.attachment();        long bytesRead = sc.read(buf);        while(bytesRead>0){            buf.flip();            while(buf.hasRemaining()){                System.out.print((char)buf.get());            }            System.out.println();            buf.clear();            bytesRead = sc.read(buf);        }        if(bytesRead == -1){            sc.close();        }    }    public static void handleWrite(SelectionKey key) throws IOException{        ByteBuffer buf = (ByteBuffer)key.attachment();        buf.flip();        SocketChannel sc = (SocketChannel) key.channel();        while(buf.hasRemaining()){            sc.write(buf);        }        buf.compact();    }}

 

5、管道(Pipe)

Java NIO 管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。

 

public class TestPipe {@Testpublic void test1() throws IOException{//1. 获取管道Pipe pipe = Pipe.open();//2. 将缓冲区中的数据写入管道ByteBuffer buf = ByteBuffer.allocate(1024);Pipe.SinkChannel sinkChannel = pipe.sink();buf.put("通过单向管道发送数据".getBytes());buf.flip();sinkChannel.write(buf);//3. 读取缓冲区中的数据Pipe.SourceChannel sourceChannel = pipe.source();buf.flip();int len = sourceChannel.read(buf);System.out.println(new String(buf.array(), 0, len));sourceChannel.close();sinkChannel.close();}}

 

 public static void method1(){        Pipe pipe = null;        ExecutorService exec = Executors.newFixedThreadPool(2);        try{            pipe = Pipe.open();            final Pipe pipeTemp = pipe;            exec.submit(new Callable<Object>(){                @Override                public Object call() throws Exception                {                    Pipe.SinkChannel sinkChannel = pipeTemp.sink();//向通道中写数据                    while(true){                        TimeUnit.SECONDS.sleep(1);                        String newData = "Pipe Test At Time "+System.currentTimeMillis();                        ByteBuffer buf = ByteBuffer.allocate(1024);                        buf.clear();                        buf.put(newData.getBytes());                        buf.flip();                        while(buf.hasRemaining()){                            System.out.println(buf);                            sinkChannel.write(buf);                        }                    }                }            });            exec.submit(new Callable<Object>(){                @Override                public Object call() throws Exception                {                    Pipe.SourceChannel sourceChannel = pipeTemp.source();//向通道中读数据                    while(true){                        TimeUnit.SECONDS.sleep(1);                        ByteBuffer buf = ByteBuffer.allocate(1024);                        buf.clear();                        int bytesRead = sourceChannel.read(buf);                        System.out.println("bytesRead="+bytesRead);                        while(bytesRead >0 ){                            buf.flip();                            byte b[] = new byte[bytesRead];                            int i=0;                            while(buf.hasRemaining()){                                b[i]=buf.get();                                System.out.printf("%X",b[i]);                                i++;                            }                            String s = new String(b);                            System.out.println("=================||"+s);                            bytesRead = sourceChannel.read(buf);                        }                    }                }            });        }catch(IOException e){            e.printStackTrace();        }finally{            exec.shutdown();        }    }

6、Path、Paths、Files 类

public class TestNIO_2 {//自动资源管理:自动关闭实现 AutoCloseable 接口的资源@Testpublic void test8(){try(FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE)){ByteBuffer buf = ByteBuffer.allocate(1024);inChannel.read(buf);}catch(IOException e){}}/*Files常用方法:用于操作内容SeekableByteChannel newByteChannel(Path path, OpenOption…how) : 获取与指定文件的连接,how 指定打开方式。DirectoryStream newDirectoryStream(Path path) : 打开 path 指定的目录InputStream newInputStream(Path path, OpenOption…how):获取 InputStream 对象OutputStream newOutputStream(Path path, OpenOption…how) : 获取 OutputStream 对象 */@Testpublic void test7() throws IOException{SeekableByteChannel newByteChannel = Files.newByteChannel(Paths.get("1.jpg"), StandardOpenOption.READ);DirectoryStream<Path> newDirectoryStream = Files.newDirectoryStream(Paths.get("e:/"));for (Path path : newDirectoryStream) {System.out.println(path);}}/*Files常用方法:用于判断boolean exists(Path path, LinkOption … opts) : 判断文件是否存在boolean isDirectory(Path path, LinkOption … opts) : 判断是否是目录boolean isExecutable(Path path) : 判断是否是可执行文件boolean isHidden(Path path) : 判断是否是隐藏文件boolean isReadable(Path path) : 判断文件是否可读boolean isWritable(Path path) : 判断文件是否可写boolean notExists(Path path, LinkOption … opts) : 判断文件是否不存在public static <A extends BasicFileAttributes> A readAttributes(Path path,Class<A> type,LinkOption... options) : 获取与 path 指定的文件相关联的属性。 */@Testpublic void test6() throws IOException{Path path = Paths.get("e:/nio/hello7.txt");//System.out.println(Files.exists(path, LinkOption.NOFOLLOW_LINKS));BasicFileAttributes readAttributes = Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);System.out.println(readAttributes.creationTime());System.out.println(readAttributes.lastModifiedTime());DosFileAttributeView fileAttributeView = Files.getFileAttributeView(path, DosFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);fileAttributeView.setHidden(false);}/*Files常用方法:Path copy(Path src, Path dest, CopyOption … how) : 文件的复制Path createDirectory(Path path, FileAttribute<?> … attr) : 创建一个目录Path createFile(Path path, FileAttribute<?> … arr) : 创建一个文件void delete(Path path) : 删除一个文件Path move(Path src, Path dest, CopyOption…how) : 将 src 移动到 dest 位置long size(Path path) : 返回 path 指定文件的大小 */@Testpublic void test5() throws IOException{Path path1 = Paths.get("e:/nio/hello2.txt");Path path2 = Paths.get("e:/nio/hello7.txt");System.out.println(Files.size(path2));//Files.move(path1, path2, StandardCopyOption.ATOMIC_MOVE);}@Testpublic void test4() throws IOException{Path dir = Paths.get("e:/nio/nio2");//Files.createDirectory(dir);Path file = Paths.get("e:/nio/nio2/hello3.txt");//Files.createFile(file);Files.deleteIfExists(file);}@Testpublic void test3() throws IOException{Path path1 = Paths.get("e:/nio/hello.txt");Path path2 = Paths.get("e:/nio/hello2.txt");Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING);}/*Paths 提供的 get() 方法用来获取 Path 对象:Path get(String first, String … more) : 用于将多个字符串串连成路径。Path 常用方法:boolean endsWith(String path) : 判断是否以 path 路径结束boolean startsWith(String path) : 判断是否以 path 路径开始boolean isAbsolute() : 判断是否是绝对路径Path getFileName() : 返回与调用 Path 对象关联的文件名Path getName(int idx) : 返回的指定索引位置 idx 的路径名称int getNameCount() : 返回Path 根目录后面元素的数量Path getParent() :返回Path对象包含整个路径,不包含 Path 对象指定的文件路径Path getRoot() :返回调用 Path 对象的根路径Path resolve(Path p) :将相对路径解析为绝对路径Path toAbsolutePath() : 作为绝对路径返回调用 Path 对象String toString() : 返回调用 Path 对象的字符串表示形式 */@Testpublic void test2(){Path path = Paths.get("e:/nio/hello.txt");System.out.println(path.getParent());System.out.println(path.getRoot());//Path newPath = path.resolve("e:/hello.txt");//System.out.println(newPath);Path path2 = Paths.get("1.jpg");Path newPath = path2.toAbsolutePath();System.out.println(newPath);System.out.println(path.toString());}@Testpublic void test1(){Path path = Paths.get("e:/", "nio/hello.txt");System.out.println(path.endsWith("hello.txt"));System.out.println(path.startsWith("e:/"));System.out.println(path.isAbsolute());System.out.println(path.getFileName());for (int i = 0; i < path.getNameCount(); i++) {System.out.println(path.getName(i));}}}