java NIO的使用

package com.ilike.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import org.junit.Test;

/**
*
* @author 桑伟东
*
* 一、使用NIO完成网络通信的三个核心
* 1.通道(channel):负责连接
* SelectableChannel
* |–SocketChannel
* |–ServerSocketChannel
* |–DataGramChannel
*
* |Pipe.SinkChannel
* |Pipe.SourceChannel
*
* 2.缓冲区(Buffer):负责数据的存储
*
* 3.选择器(Selector):是SelectableChannel的多路复用器。用于监控SelectableChannel的IO状况
*
*/
public class TestBlockingNio {

//客户端
@Test
public void client() throws IOException{
    //1.获取通道
    SocketChannel sChannel=SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
    FileChannel inChannel=FileChannel.open(Paths.get("a.jpg"), StandardOpenOption.READ);

    //2.获取指定大小的缓冲区
    ByteBuffer buffer=ByteBuffer.allocate(1024);

    //3.读取本地文件,并发送到服务端去
    while (inChannel.read(buffer)!=-1) {
        buffer.flip();
        sChannel.write(buffer); 
        buffer.clear();
    }
    //4.关闭通道
     inChannel.close();
     sChannel.close();
}



//服务端
@Test
public void server() throws IOException{
    //1.获取通道
    ServerSocketChannel ssChannel=ServerSocketChannel.open();
    FileChannel outChannel=FileChannel.open(Paths.get("b.jpg"),StandardOpenOption.WRITE, StandardOpenOption.CREATE);
    //2.绑定连接
    ssChannel.bind(new InetSocketAddress(9898));
    //3.获取客户端连接的通道
     SocketChannel  socketChannel=ssChannel.accept();
    //4.分配指定大小的缓冲区 
     ByteBuffer buffer=ByteBuffer.allocate(1024);
    //5.接受客户端的数据
     while (socketChannel.read(buffer)!=-1) {
         buffer.flip();
         outChannel.write(buffer);
         buffer.clear();
    }
     //6.关闭通道
     socketChannel.close();
     outChannel.close();
     ssChannel.close();

}

}

package com.ilike.nio;

import java.nio.ByteBuffer;

import org.junit.Test;
/**
* Buffer缓冲区
* @author 桑伟东
*
*/

public class TestBuffer {

@Test
public void testByteBuffer3(){
    //1.分配直接缓冲区
    ByteBuffer buffer=ByteBuffer.allocateDirect(1024);
    //2.判断是否是直接缓冲区
    System.out.println(buffer.isDirect());

}

@Test
public void testByteBuffer2(){
    //1.创建一个容量为1024个字节的缓冲区
    ByteBuffer buffer=ByteBuffer.allocate(1024);
    String src="abcde";
    //2.放入数据
    buffer.put(src.getBytes());
    //3.切换到读模式
    buffer.flip();
    byte [] dst=new byte[buffer.limit()];
    buffer.get(dst,0,2);
    System.out.println(new String(dst));
    System.out.println(buffer.position());
    //4.标记position的位置
    buffer.mark();
    //5.再次读取
    buffer.get(dst,2,2);
    System.out.println(new String(dst,2,2));
    System.out.println(buffer.position());
    //6.让position回到mark标记的位置
    System.out.println("---------------");
    //该方法可以让position回到之前mark标记的位置
    buffer.reset();
    System.out.println(buffer.position());

    //7.获取缓冲区中可以操作的数据
      if(buffer.hasRemaining()){
          //读取可以操作的数据的个数
          System.out.println(buffer.remaining());
      }
    }


@Test
public void testByteBuffer1(){
    //1.创建一个容量为1024个字节的缓冲区
    ByteBuffer buffer=ByteBuffer.allocate(1024);
    String src="abcde";

    System.out.println("-----------allocate()----------------");
    System.out.println(buffer.position());
    System.out.println(buffer.limit());
    System.out.println(buffer.capacity());

    //2.通过put()写入数据
    buffer.put(src.getBytes());
    System.out.println("-----------put()----------------");
    System.out.println(buffer.position());
    System.out.println(buffer.limit());
    System.out.println(buffer.capacity());

    //3.通过flip()切换到读取数据模式
    buffer.flip();
    System.out.println("-----------flip()----------------");
    System.out.println(buffer.position());
    System.out.println(buffer.limit());
    System.out.println(buffer.capacity());

    //4.通过get()读取数据
    byte[] dst=new byte[buffer.limit()];
    buffer.get(dst);
    System.out.println(new String(dst));
    System.out.println("-----------get()----------------");
    System.out.println(buffer.position());
    System.out.println(buffer.limit());
    System.out.println(buffer.capacity());

    //5.rewind():可以重复读数据
    buffer.rewind();
    System.out.println("-----------rewind()----------------");
    System.out.println(buffer.position());
    System.out.println(buffer.limit());
    System.out.println(buffer.capacity());

    //6.通过claer()清空缓冲区,但是里面的数据依然存在,只是出于被遗忘状态
    buffer.clear();
    System.out.println("-----------claer()----------------");
    System.out.println(buffer.position());
    System.out.println(buffer.limit());
    System.out.println(buffer.capacity());
    System.out.println((char)buffer.get(0));
}

}

package com.ilike.nio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Map;

import org.junit.Test;

/**
* 一.通道(channel):用于源节点和目标节点的连接,在java NIO中负责缓冲区中数据的传输
* channel本身不存储数据,因此他需要配合缓冲区来进行数据传输
*
* 二.通道的主要实现类
* FileChannel
* SocketChannel
* SeverSocketChannel
* DataGramChannel
* 三.获取通道
* 1.java针对支持通道的类提供了getChannel()的方法
* 本地IO:
* FileInputStream/FileOutputStream
* RandomAccessFile
* 网络IO: Socket
* SeverSocket
* DataGramSocket
* 2.在jdk1.7中的NIO.2中针对各个静态方法提供了open();
* 3.在jdk1.7中的NIO.2中的files工具类newByteChannel()方法
*
* 四.通道之间的数据传输
* transferFrom();
* transferTo();
*
* 五.分散(Scatter)与聚集(Gather)
* 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中去
* 聚集写入(Gathering writes):将多个缓冲区中的数据聚集到通道中
*
* 六.字符集 Charset
* 编码:字符串–>字节数组
* 解码:字节数组–>字符串
*
*
*
* @author 桑伟东
*
*/
public class TestChannel {

//字符集
@Test
public void testCharset2() throws IOException {
    Charset charset=Charset.forName("GBK");
    //获取编码器
    CharsetEncoder ce=charset.newEncoder();
    //获取解码器
    CharsetDecoder cd=charset.newDecoder();

    //创建字符缓冲区
    CharBuffer cb=CharBuffer.allocate(1024);
    cb.put("桑伟东是工程师");
    //切换到读模式
    cb.flip();
    //进行编码
     ByteBuffer bb=ce.encode(cb);
      for (int i = 0; i < bb.limit(); i++) {
        System.out.println(bb.get());
    }

     //进行解码
      bb.flip();
      CharBuffer cb2= cd.decode(bb);
      System.out.println(cb2.toString());
}

//字符集
@Test
public void testCharset1() {
    //获取java中支持的字符集
    Map charsets=Charset.availableCharsets();
    for (String key : charsets.keySet()) {
        System.out.println(key+":"+charsets.get(key));
    }
}




//分散与聚集
 @Test
  public void testChannel4() throws IOException {
     RandomAccessFile raf1=new RandomAccessFile("a.txt", "rw");
     //1.获取通道
     FileChannel inChannel=raf1.getChannel();
     //2.分配指定大小的缓冲区
     ByteBuffer buffer1=ByteBuffer.allocate(200);
     ByteBuffer buffer2=ByteBuffer.allocate(800);
     //3.分散读取
     ByteBuffer[] buffers={buffer1,buffer2};
     inChannel.read(buffers);
     for (ByteBuffer byteBuffer : buffers) {
         byteBuffer.flip();
    }
     System.out.println(new String(buffers[0].array()));
     System.out.println(new String(buffers[1].array()));
     inChannel.close();

     RandomAccessFile raf2=new RandomAccessFile("b.txt", "rw");
     //4.获取写入通道
     FileChannel outChannel=raf2.getChannel();
     //5.聚集写入
     outChannel.write(buffers);
     outChannel.close();
     raf2.close();
     raf1.close();

 }



//通道之间的数据传输(直接缓冲区)
 @Test
  public void testChannel3() throws IOException {
     //1.获取通道
     FileChannel inChannel=FileChannel.open(Paths.get("a.jpg"), StandardOpenOption.READ);
     FileChannel outChannel=FileChannel.open(Paths.get("b.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
      //2.传输数据
     // inChannel.transferTo(0, inChannel.size(), outChannel);
     outChannel.transferFrom(inChannel, 0, inChannel.size());
     //3.关闭通道
     outChannel.close();
     inChannel.close(); 
 }

//2.使用直接缓冲区完成文件的复制(内存映射文件)
  @Test
  public void testChannel2() throws IOException {
      long start=System.currentTimeMillis();
    //1.获取通道
      FileChannel inChannel=FileChannel.open(Paths.get("a.jpg"), StandardOpenOption.READ);
      FileChannel outChannel=FileChannel.open(Paths.get("b.jpg"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
   //2.内存映射文件
      MappedByteBuffer inBuffer= inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
      MappedByteBuffer outBuffer=outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
    //3.直接对缓冲区中的数据进行操作
      byte[] dst=new byte[inBuffer.limit()];
      inBuffer.get(dst);
      outBuffer.put(dst);
      outChannel.close();
      inChannel.close();
      long end=System.currentTimeMillis();
      System.out.println("共耗时:"+(end-start));
}



//1.使用通道完成文件的复制(非直接缓冲区)
@Test
public void testChannel1() {
    long start=System.currentTimeMillis();
    // 1.创建流对象
    FileInputStream fis = null;
    FileOutputStream fos = null;
    // 2.获取通道
    FileChannel inChannel = null;
    FileChannel outChannel = null;
    try {
        fis = new FileInputStream("a.jpg");
        fos = new FileOutputStream("b.jpg");
        inChannel = fis.getChannel();
        outChannel = fos.getChannel();
        // 3.分配一个指定大小的缓存区
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        // 4.读写数据
        while (inChannel.read(buffer) != -1) {
            // 切换到读模式
            buffer.flip();
            // 将数据放入写通道
            outChannel.write(buffer);
            // 清空缓冲区
            buffer.clear();
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } finally {
        // 5.释放资源
        if (outChannel != null) {
            try {
                outChannel.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

        if (inChannel != null) {
            try {
                inChannel.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }
      long end=System.currentTimeMillis();
      System.out.println("共耗时:"+(end-start));
}

}

package com.ilike.nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;
import java.nio.channels.Pipe.SinkChannel;
import java.nio.channels.Pipe.SourceChannel;
import org.junit.Test;

public class TestPipe {

@Test
public void test1() throws IOException{
    //1.获取通道
    Pipe pipe=Pipe.open();

    //2.将缓冲区中的数据写入管道
    ByteBuffer buffer=ByteBuffer.allocate(1024);

    SinkChannel sinkChannel=    pipe.sink();
    buffer.put("通过单向管道发送数据!!!".getBytes());
    buffer.flip();
    sinkChannel.write(buffer);

    //3.读取数据
    SourceChannel  sourceChannel=  pipe.source();
    ByteBuffer buffer2=ByteBuffer.allocate(1024);
    int len=sourceChannel.read(buffer2);
    buffer2.flip();
    System.out.println(new String(buffer2.array(),0,len));
    sourceChannel.close();
    sinkChannel.close();    
}

}

package com.ilike.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

import org.junit.Test;

public class TestBlockingNio2 {

/**
 * 客户端
 * @throws IOException
 */
@Test
public void client() throws IOException {
    //1.获取通道
    SocketChannel sChannel=SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
    FileChannel fChannel=FileChannel.open(Paths.get("a.jpg"), StandardOpenOption.READ);
    //2.分配指定大小的缓冲区
    ByteBuffer buffer=ByteBuffer.allocate(1024);
    //3.读取数据发送到服务器
    while (fChannel.read(buffer)!=-1) {
        buffer.flip();
        sChannel.write(buffer);
        buffer.clear();
    }
    sChannel.shutdownOutput();

    //4.获取服务端的反馈
      int len=0;
    while ((len=sChannel.read(buffer))!=-1) {
        buffer.flip();
        System.out.println(new String(buffer.array(),0, len));
        buffer.clear();
    }
    //5.关闭资源
    fChannel.close();
    sChannel.close();
}

/**
 * 服务端
 * @throws IOException
 */
@Test
public void server() throws IOException {
    //1.获取通道
    ServerSocketChannel ssChannel=ServerSocketChannel.open();
    FileChannel outChannel=FileChannel.open(Paths.get("b.jpg"), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
    ssChannel.bind(new InetSocketAddress(9898));
    //2.与客户端建立连接
     SocketChannel  sChannel=ssChannel.accept();
    //3.分配指定大小的缓冲区
     ByteBuffer buffer=ByteBuffer.allocate(1024);
    //4.读取客户端的数据
     while (sChannel.read(buffer)!=-1) {
        buffer.flip();
        outChannel.write(buffer);
        buffer.clear();
    }
     //5.给客户端给一个成功的消息
     buffer.put("成功".getBytes());
     buffer.flip();
     sChannel.write(buffer);
     //6.关闭通道
     sChannel.close();
     outChannel.close();
     ssChannel.close();
}

}

package com.ilike.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
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.util.Date;
import java.util.Iterator;
import java.util.Scanner;

import org.junit.Test;

/**
*
* @author 桑伟东
*
* 一、使用NIO完成网络通信的三个核心
* 1.通道(channel):负责连接
* SelectableChannel
* |–SocketChannel
* |–ServerSocketChannel
* |–DataGramChannel
*
* |Pipe.SinkChannel
* |Pipe.SourceChannel
*
* 2.缓冲区(Buffer):负责数据的存储
*
* 3.选择器(Selector):是SelectableChannel的多路复用器。用于监控SelectableChannel的IO状况
*
*/
public class TestNonBlockingNio {
/**
* 客户端
* @throws IOException
*/
@Test
public void client() throws IOException {
//1.获取通道
SocketChannel sChannel=SocketChannel.open(new InetSocketAddress(“127.0.0.1”, 9898));
//2.切换到非阻塞模式
sChannel.configureBlocking(false);
//3.分配指定大小的缓冲区
ByteBuffer buffer=ByteBuffer.allocate(1024);
//4.发送数据
Scanner sc=new Scanner(System.in);
while (sc.hasNext()) {
buffer.put((new Date().toString()+”\n”+sc.nextLine()).getBytes());
buffer.flip();
sChannel.write(buffer);
buffer.clear();
}
//5.关闭通道
sChannel.close();
}
/**
* 服务端
* @throws IOException
*/
@Test
public 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 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 readChannel=(SocketChannel) sk.channel();
//14.读取数据
ByteBuffer buffer=ByteBuffer.allocate(1024);
int len=0;
while ((len=readChannel.read(buffer))>0) {
buffer.flip();
System.out.println(new String(buffer.array(),0,len));
buffer.clear();
}

            }
            //15.取消选择键SelectionKey
            it.remove();
        }
    }
}

}

package com.ilike.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Date;
import java.util.Iterator;
import java.util.Scanner;

import org.junit.Test;

public class TestNonBlockingNio2 {

@Test
public void send() throws IOException {
    //1.获取通道
    DatagramChannel dc=DatagramChannel.open();
    //2.切换到非阻塞模式
    dc.configureBlocking(false);
    //3.分配指定大小的缓冲区
    ByteBuffer buffer=ByteBuffer.allocate(1024);
    //4.发送数据
    Scanner sc=new Scanner(System.in);
    while (sc.hasNext()) {
        buffer.put((new Date().toString()+":\n"+sc.nextLine()).getBytes());
        buffer.flip();
        dc.send(buffer, new InetSocketAddress("127.0.0.1", 9898));
        buffer.clear();
    }
    //5.关闭通道
    dc.close();
}

@Test
public void receive() throws IOException {
    //1.获取通道
    DatagramChannel dc=DatagramChannel.open();
    //2.切换到非阻塞模式
    dc.configureBlocking(false);
    //3.绑定端口号
    dc.bind(new InetSocketAddress(9898));
    //4.获取选择器
    Selector selector=Selector.open();
    //5.将该通道注册在这个选择器上
    dc.register(selector, SelectionKey.OP_READ);
    while (selector.select()>0) {
         Iterator it=selector.selectedKeys().iterator();
        while (it.hasNext()) {
            SelectionKey  sk=it.next();
            if(sk.isReadable()){
            ByteBuffer buffer=ByteBuffer.allocate(1024);
            dc.receive(buffer);
            buffer.flip();
            System.out.println(new String(buffer.array(),0,buffer.limit()));
            buffer.clear();
            }
        }
        it.remove();
    }
}

}

你可能感兴趣的:(java技术)