• JAVA中的NIO(一)


    1、IO与NIO


      IO就是普通的IO,或者说原生的IO。特点:阻塞式、内部无缓冲,面向流。

      NIO就是NEW IO,比原生的IO要高效。特点:非阻塞、内部有缓存,面向缓冲。

      要实现高效的IO操作,尤其是服务器端程序时,需要使用NIO进行开发。

    2、NIO的理解


      NIO就是中引入了通道和缓冲器的概念。我们可以把文件想想成一个水池,以前是我们使用普通IO时是直接从池中取水。现在的NIO就相当于在水池中引出来一个水管,并将水管的另一端放在一个跟小的蓄水池中。当我们需要水时直接从蓄水池中取水。NIO中蓄水池就是Buffer类,我们可以设置这个类的大小,而这个蓄水池也只能放基本数据类型。而所谓的水管就是Channel了。

     具体buffer类:

    • ByteBuffer
    • CharBuffer
    • DoubleBuffer
    • FloatBuffer
    • IntBuffer
    • LongBuffer
    • ShortBuffer

     具体的channel类

    • FileChannel
    • DatagramChannel
    • SocketChannel
    • ServerSocketChannel

    2、NIO的使用


    1.buffer的三大属性

    • capacity  缓冲区的最大容量
    • limit  读写的限制,比如读的时候缓冲区就只有5个字节,那么limit就等于4。当写缓冲区时,limit一般指向缓冲区的末尾
    • position   当前读写的位置
    package com.dy.xidian;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    public class GetChannel {
        public static final int BSIZE = 1024;
        @SuppressWarnings("resource")
        public static void main(String[] args) throws IOException {
            FileChannel fc = new FileOutputStream("E:/html/utf-8.php").getChannel();
            // 将传入的数组作为ByteBuffer的储存器,就是所谓的缓冲区
            fc.write(ByteBuffer.wrap("some text".getBytes()));
            fc.close();
            fc = new RandomAccessFile("E:/html/utf-8.php", "rw").getChannel();
            // 通过position更改管道的位置,我们可以认为水池中水管的位置是不固定
            fc.position(fc.size());
            fc.write(ByteBuffer.wrap("Some more".getBytes()));
            fc.close();
            fc = new FileInputStream("E:/html/utf-8.php").getChannel();
            ByteBuffer buff = ByteBuffer.allocate(BSIZE);
            fc.read(buff);
         // 重置缓冲区,令limit=position,position=0,read之后必须的操作 buff.flip();
    while (buff.hasRemaining()) System.out.println((char) buff.get()); } }

    2.文件copy


     

    package com.dy.xidian;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    public class FileCopy {
        public static final int BSIZE = 1024;
        @SuppressWarnings("resource")
        public static void main(String[] args) throws IOException {
            if (args.length != 2) {
                System.out.println("arguments: sourcefile destfile");
                System.exit(1);
            }
            FileChannel in = new FileInputStream(args[0]).getChannel();
            FileChannel out = new FileOutputStream(args[1]).getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(BSIZE);
            while (in.read(buffer) != -1) {
                //limit=position, position=0
                buffer.flip();
                out.write(buffer);
                //position=0,limit=capacity
                buffer.clear();
            }
        }
    }

    改进:将两个管道直接连接起来

    package com.dy.xidian;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.channels.FileChannel;
    
    public class GetChannel {
        public static final int BSIZE = 1024;
        @SuppressWarnings("resource")
        public static void main(String[] args) throws IOException {
            if (args.length != 2) {
                System.out.println("arguments: sourcefile destfile");
                System.exit(1);
            }
            FileChannel in = new FileInputStream(args[0]).getChannel();
            FileChannel out = new FileOutputStream(args[1]).getChannel();
         //0:源文件的起始位置,in.size():数据量,out目的文件 in.transferTo(
    0, in.size(), out); } }

    3.转换数据

    package com.dy.xidian;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    import java.nio.charset.Charset;
    
    public class BufferToText {
        private static final int BSIZE = 1024;
    
        @SuppressWarnings("resource")
        public static void main(String[] args) throws IOException {
            /************** 写操作 ****************/
            FileChannel fc = new FileOutputStream("data2.txt").getChannel();
            // ByteBuffer为字节缓冲器,我们向缓冲器中输入数据时应对其进行编码
            // 从缓冲器中读数据时应该进行解码
            fc.write(ByteBuffer.wrap("Some text".getBytes("utf-8")));
            fc.close();
            /************** 读操作 ****************/
            fc = new FileInputStream("data2.txt").getChannel();
            ByteBuffer buff = ByteBuffer.allocate(BSIZE);
            fc.read(buff);
            buff.flip();
            System.out.println(buff.asCharBuffer());
            // position=0
            buff.rewind();
            //设置字符集,解决乱码问题
            String encoding = System.getProperty("file.encoding");
            System.out.println("Decoded using " + encoding + ": "
                    + Charset.forName(encoding).decode(buff));
            //通过charBuffer向ByteBuffer中写入
            fc = new FileOutputStream("data2.txt").getChannel();
            buff = ByteBuffer.allocate(24);
            buff.asCharBuffer().put("Some text");
            fc.write(buff);
            fc.close();
            fc = new FileInputStream("data2.txt").getChannel();
            buff.clear();
            fc.read(buff);
            buff.flip();
            System.out.println(buff.asCharBuffer());
        }
    }

    4.获取基本数据类型

    package com.dy.xidian;
    
    import java.nio.ByteBuffer;
    
    public class GetData {
        private static final int BSIZE = 1024;
        public static void main(String[] args) {
            ByteBuffer bb = ByteBuffer.allocate(BSIZE);
            int i = 0;
            // 缓冲区自动被初始化为0
            while (i++ < bb.limit())
                // limit不变,position++
                if (bb.get() != 0)
                    System.out.println("nonzero!");
            System.out.println("i = " + i);
            // position = 0
            bb.rewind();
            /* 以字符的方式向缓冲区写 */
            bb.asCharBuffer().put("Howdy");
            char c;
            while ((c = bb.getChar()) != 0)
                System.out.print(c + " ");
            System.out.println("");
            bb.rewind();
            /* 以short类型向缓冲区写 */
            bb.asShortBuffer().put((short) 471);
            System.out.println(bb.getShort());
            bb.rewind();
            /* 以int类型向缓冲区写 */
            bb.asIntBuffer().put(99471142);
            System.out.println(bb.getInt());
            bb.rewind();
            /* 以long类型向缓冲区写 */
            bb.asLongBuffer().put(99471142);
            System.out.println(bb.getLong());
            bb.rewind();
            /* 以float类型向缓冲区写 */
            bb.asFloatBuffer().put(99471142);
            System.out.println(bb.getFloat());
            bb.rewind();
            /* 以double类型向缓冲区写 */
            bb.asDoubleBuffer().put(99471142);
            System.out.println(bb.getDouble());
            bb.rewind();
        }
    }

    代码中使用到了视图缓冲器(asIntBuffer、asFloatBuffer...),通过视图缓冲器来操作底层的ByteBuffer使得编程更加方便。不同的视图缓冲器对底层数组的影响是不同的,比如char视图会一次读两个字节,position则会移动两位,这点需要注意。ByteBuffer是以大端(低地址存高数据位)的方式存储数据。

    4.相邻字符交换

    package com.dy.xidian;
    
    import java.io.UnsupportedEncodingException;
    import java.nio.ByteBuffer;
    import java.nio.CharBuffer;
    
    public class Exchange {
        public static void main(String[] args) throws UnsupportedEncodingException {
            char[] data = "usingbuffers".toCharArray();
            System.out.println("char[] data = " + data.length);
            ByteBuffer bb = ByteBuffer.allocate(data.length * 2);
            System.out.println("bytebuffer.capacity = " + bb.capacity());
            System.out.println("bytebuffer.limit = " + bb.limit());
            CharBuffer cb = bb.asCharBuffer();
            cb.put(data);
            System.out.println("charBuffer.limit = " + cb.limit());
            char c1, c2;
            cb.rewind();
            while (cb.hasRemaining()) {
                cb.mark();
                c1 = cb.get();
                c2 = cb.get();
                cb.reset();
                cb.put(c2).put(c1);
            }
            cb.rewind();
            System.out.println(cb);
        }
    }

    3、参考文章


    http://www.iteye.com/magazines/132-Java-NIO#579

    http://blog.csdn.net/linxcool/article/details/7771952

    http://blog.csdn.net/baple/article/details/12749005

    http://www.cnblogs.com/mjorcen/p/3992245.html

  • 相关阅读:
    HTTP
    nginx反向代理和负载均衡
    keepalive
    lnmp
    DNS
    jumpserver跳板机
    博客已搬家到CSDN
    JAVA中关于上传图片到数据库和从数据库取出显示图片的问题
    checkbox的标签和全选中问题
    SOCKET
  • 原文地址:https://www.cnblogs.com/xidongyu/p/5414518.html
Copyright © 2020-2023  润新知