zoukankan      html  css  js  c++  java
  • Java NIO

    Java NIO:

      JAVA NIO核心部分是 Channel Buffer Selector。

      所有IO在NIO中都从一个Channel开始,Channel有点像流,数据可以从Channel读到Buffer中,也可从Buffer读到Channel。Selector允许单线程处理多个Channel。

    1、Buffer

      步骤:1)写入数据到Buffer;   2)调用filp()方法;  3)从Buffer中读取数据;  4)调用clear()或者compact()方法

      

      capacity:数组总长度;

      position:下一个要操作的数据元素的位置

      limit:缓存区数组总不可操作的下一个元素的位置

      filp()方法将Buffer从写模式切换到读模式,position的值付给limit,然后position=0,读position->limit之间的数据。

      clear()清空整个缓存区,compect()只清楚已经读过的数据,未读的数据移到缓冲区的起始处,新写入的数据放到缓冲区未读数据后面。

      Buffer的分配:

        ByteBuffer buf=ByteBuffer.allocate(48);

        CharBuffer buf=CharBuffer.allocate(1024);

      Buffer的类型:ByteBuffer  CharBuffer  DoubleBuffer  IntBuffer  ...

      Buffer中数据的读写操作:

        写:

          1)从Channel写到buffer

            int bytesRead=inChannel.read(buf);

          2)通过put()方法写入Buffer

            buf.put(127)

        读:

          1)从Buffer读取数据到Channel

            Int bytesWriten=inChannel.write(buf);

          2)使用get()方法从Buffer中读取数据

            byte aByte=buf.get();

    package com.zhao.FileChannel;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    public class FileChannelDemo {
        /**
         * FileChannel从文件中读写数据
         * 
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            FileChannelDemo demo=new FileChannelDemo();
    //        demo.read();
            demo.write();
        }
    
        public void read() throws IOException {
            File file = new File("fileChannel.txt");
            if (!file.exists()) {
                file.createNewFile();
            }
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
            /*
             * 在使用FileChannel之前,必须先打开它。但是,我们无法直接打开一个FileChannel,需要通过使用一个InputStream、
             * OutputStream或RandomAccessFile来获取一个FileChannel实例
             */
            FileChannel fileChannel = randomAccessFile.getChannel();
            // 创建了一个48个byte的数组缓冲区
            /**
             * capacity:缓冲区数组的总长度 position:下一个要操作的数据元素的位置
             * limit:缓冲区数组中不可操作的下一个元素的位置。(在写模式下,limit就是最多能写多少数据;在读模式下,
             * limit就是最多能读多少数据)
             */
            ByteBuffer buffer = ByteBuffer.allocate(48);
            /*
             * 将字节序列从此通道读入给定的缓冲区 。返回:读取的字节数,可能为零,如果该通道已到达流的末尾,则返回 -1
             */
            int count = fileChannel.read(buffer);
            System.out.println("读到字节数: " + count);
            while (count != -1) {
                // flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值
                buffer.flip();
                // 在position和limit之间有元素
                while (buffer.hasRemaining()) {
                    System.out.print((char) buffer.get());
                }
                // clear方法就是让position设回0,limit与capacity相等
                buffer.clear();
                count = fileChannel.read(buffer);
                System.out.println("
    终止条件: " + count);
                /*
                 * compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。
                 * limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。
                 */
            }
            randomAccessFile.close();
        }
        public void write() throws IOException{
            File file=new File("fileChannel.txt");
            if (!file.exists()) {
                file.createNewFile();
            }
            RandomAccessFile accessFile=new RandomAccessFile(file, "rw");
            FileChannel channel=accessFile.getChannel();
            
            String str="Channel Buffer Selector "+System.currentTimeMillis();
            ByteBuffer buffer=ByteBuffer.allocate(1024);
            buffer.clear();
            buffer.put(str.getBytes());
            System.out.println("Position: "+channel.position());
            buffer.flip();
            while(buffer.hasRemaining()){
                channel.write(buffer);
            }
            System.out.println("Channel Size: "+channel.size());
            channel.close();
            accessFile.close();
        }
    
    }

    2:Channel

      Java NIO的通道类似流,但有些不同。

        既可以在通道中读取数据,又可以写数据到通道,但流的读写是单向的。

        通道可以异步读写。

        通道的数据综上先读到一个Buffer或者从一个Buffer中写入。

      FileChannel:从文件中读写数据

      DatagramChannel: 能通过UDP读写网络中的数据

      SocketChannel:能通过TCP读写网络中的数据

      ServerSocketChannel 可以监听新进来的TCP连接,对每一个新进来的连接都会创建一个SocketChannel.

     1)TCP

    //客户端

    package com.zhao.TCPSocket;
    
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.SocketChannel;
    
    public class Client {
        /**
         * Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道
         * 
         * @author zhao
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            // 打开套接字通道
            SocketChannel socketChannel = SocketChannel.open();
            //可以设置 SocketChannel 为非阻塞模式(non-blocking mode).设置之后,就可以在异步模式下调用connect(), read() 和write()了
    //        socketChannel.configureBlocking(false);
            // 创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值
            InetAddress remote = InetAddress.getLocalHost();
            // 连接此通道的套接字
            socketChannel.connect(new InetSocketAddress(remote, 8888));
    
            // 从socketChannel中读取数据
    //        ByteBuffer buffer = ByteBuffer.allocate(1024);
    //        int bytesRead = socketChannel.read(buffer);
    
            // 写入socketChannel
            ByteBuffer buffer2 = ByteBuffer.allocate(1024);
            String str = "zhao " + System.currentTimeMillis();
            buffer2.put(str.getBytes());
    
            buffer2.flip();
            while (buffer2.hasRemaining()) {
                socketChannel.write(buffer2);
            }
    
            // 当用完SocketChannel之后调用SocketChannel.close()关闭SocketChannel
            socketChannel.close();
        }
    }

    //服务端

    package com.zhao.TCPSocket;
    
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.net.ServerSocket;
    import java.nio.ByteBuffer;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    
    public class Server {
        /**
         * Java NIO中的 ServerSocketChannel 是一个可以监听新进来的TCP连接的通道,
         * 就像标准IO中的ServerSocket一样
         * 
         * @author zhao
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            // 获取与此通道关联的服务器套接字
            ServerSocket serverSocket = serverSocketChannel.socket();
            // 创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值
            InetSocketAddress address = new InetSocketAddress(8888);
            // 将 ServerSocket 绑定到特定地址(IP 地址和端口号)
            serverSocket.bind(address);
            // serverSocketChannel设置为非阻塞模式
            serverSocketChannel.configureBlocking(false);
    
            while (true) {
                // 通过 ServerSocketChannel.accept() 方法监听新进来的连接。当
                // accept()方法返回的时候,它返回一个包含新进来的连接的 SocketChannel。因此,
                // accept()方法会一直阻塞到有新连接到达。如果把serverSocketChannel设置为非阻塞模式,accept会离开返回。所以需要判断
                SocketChannel socketChannel = serverSocketChannel.accept();
                if (socketChannel != null) {
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    buffer.clear();
                    int bytesRead = socketChannel.read(buffer);
                    if (bytesRead != -1) {
                        buffer.flip();
                        while (buffer.hasRemaining()) {
                            System.out.print((char)buffer.get());
                        }
                        bytesRead = socketChannel.read(buffer);
                    }
                }
            }
    
        }
    
    }

      2)UDP

    //客户端一

    package com.zhao.UDPSocket;
    
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.DatagramChannel;
    
    public class Client {
        /**
         * Java NIO中的DatagramChannel是一个能收发UDP包的通道。因为UDP是无连接的网络协议,所以不能像其它通道那样读取和写入。
         * 它发送和接收的是数据包
         * 
         * @author zhao
         * @param args
         * @throws IOException 
         */
        public static void main(String[] args) throws IOException {
            DatagramChannel datagramChannel=DatagramChannel.open();
            
            datagramChannel.socket().bind(new InetSocketAddress(8888));
            
    //        ByteBuffer buffer=ByteBuffer.allocate(1024);
    //        buffer.clear();
            //接收数据
    //        datagramChannel.receive(buffer);
            
            //发送数据
            ByteBuffer buffer2=ByteBuffer.allocate(1024);
            String str="zhao "+System.currentTimeMillis();
            buffer2.put(str.getBytes());
            buffer2.flip();
            InetAddress address=InetAddress.getLocalHost();
            datagramChannel.send(buffer2, new InetSocketAddress(address, 8889));
            System.out.println("发送");
            datagramChannel.close();
        }
    }

    //客户端二

    package com.zhao.UDPSocket;
    
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.DatagramChannel;
    
    public class Client2 {
    
        public static void main(String[] args) throws IOException {
            DatagramChannel datagramChannel=DatagramChannel.open();
            datagramChannel.socket().bind(new InetSocketAddress(8889));
            
            ByteBuffer buffer=ByteBuffer.allocate(1024);
            buffer.clear();
            datagramChannel.receive(buffer);
            buffer.flip();
            System.out.println("接收");
            while(buffer.hasRemaining()){
                System.out.print((char)buffer.get());
            }
            datagramChannel.close();
        }
    
    }

    3:通道之间的数据传输

    package com.zhao.FileChannel;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.channels.FileChannel;
    
    public class FileChannelTransferDemo {
    
        /**
         * FileChannel的transferFrom()方法可以将数据从源通道传输到FileChannel中
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            File file=new File("from.txt");
            if (!file.exists()) {
                file.createNewFile();
            }
            RandomAccessFile fromRandomAccessFile=new RandomAccessFile(file, "rw");
            FileChannel fromChannel=fromRandomAccessFile.getChannel();
            
            file=new File("to.txt");
            if (!file.exists()) {
                file.createNewFile();
            }
            RandomAccessFile toRandomAccessFile=new RandomAccessFile(file, "rw");
            FileChannel toChannel=toRandomAccessFile.getChannel();
            
            long position=0;
            long count=fromChannel.size();
            
            fromChannel.transferTo(position, count, toChannel);
            //toChannel.transferFrom(fromChannel, position, count);
            
        }
    
    }

    4:Scatter/Gather

      Scatter:从Channel中读取是指在读操作是将读取的数据写入到多个Buffer中

      Gather:写入Channe是指在写操作时将过个buffer的数据写入同一个Channel

    package com.zhao.buffer;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    public class Scatter_Gather {
    
        public static void main(String[] args) throws IOException {
            Scatter_Gather scatter_Gather = new Scatter_Gather();
            scatter_Gather.gather();
            scatter_Gather.scatter();
        }
    
        public void scatter() throws IOException {
            File file = new File("fileChannel.txt");
            if (!file.exists()) {
                file.createNewFile();
            }
            RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
            FileChannel channel = accessFile.getChannel();
    
            ByteBuffer buffer1 = ByteBuffer.allocate(10);
            ByteBuffer buffer2 = ByteBuffer.allocate(1024);
            ByteBuffer[] buffers = { buffer1, buffer2 };
            channel.read(buffers);
    
            buffer1.flip();
            buffer2.flip();
    
            while (buffer1.hasRemaining()) {
                System.out.print((char) buffer1.get());
            }
            System.out.println();
            while (buffer2.hasRemaining()) {
                System.out.print((char) buffer2.get());
            }
    
            buffer1.clear();
            buffer2.clear();
            accessFile.close();
        }
    
        public void gather() throws IOException {
            File file=new File("fileChannel.txt");
            if (!file.exists()) {
                file.createNewFile();
            }
            RandomAccessFile accessFile=new RandomAccessFile(file, "rw");
            FileChannel channel=accessFile.getChannel();
            
            ByteBuffer buffer=ByteBuffer.allocate(1024);
            ByteBuffer buffer2=ByteBuffer.allocate(1024);
            buffer.clear();
            buffer2.clear();
            String str="wang";
            String str2="admin";
            buffer.put(str.getBytes());
            buffer2.put(str2.getBytes());
            
            buffer.flip();
            buffer2.flip();
            ByteBuffer[] buffers={buffer,buffer2};
            System.out.println(channel.size());
            channel.write(buffers);
            channel.close();
            accessFile.close();
            
        }
    
    }

     

  • 相关阅读:
    创建的第二个随笔
    Jq基础简介
    从VG中去除PV unknown device
    redhat using publicyum
    Oracle 11g 安装文件说明
    WP8教程: 第一个WP8应用(一)
    WP8教程: 第一个WP8应用(二)
    sqlplus 的登录方式
    redhat7 安装oracle11g 缺少pdksh包
    jquery实现一个substr截取字符串的小效果
  • 原文地址:https://www.cnblogs.com/zhao307/p/5374148.html
Copyright © 2011-2022 走看看