zoukankan      html  css  js  c++  java
  • Java持久化之 -- 傲娇的NIO

    NIO

    Jdk 1.4+ New IO 面向通道和缓冲区

       所在包:java.nio

    执行流程:

    数据总数由通道写入到buffer , 或者是从buffer写入通道

     

    完全替换IO(面向流  单向的)

    三个组件:

    1. channel   通道

    2. Buffer   缓冲区

    3. Selector   选择器

    NIOIO 的区别

    1. 传统的IO面向流 ,NIO面向缓冲区

    2. 传统的IO是阻塞IO NIO是非阻塞IO(可并行,,可占位)

    3. NOI增加了新功能

    ① 由选择器

    ② 可以使用正则表达式

    ③ 支持内存映射(计算快,效率快)

    ④ 支持文件锁

    一:buffer 缓冲区

    读写两种模式

    本质上就是一个数据集          数组?集合?

    本质是一个可以写入数据,并且从中读取数据的内存!!!

    存储的是相同数据类型的数据集

    三个重要的值:

    1. Position:写入或者读取的数据的当前指针

    2. Limit:有多少数据可以写或者可以读

    3. Capacity:缓冲区的最大容量

    在写(write)模式的情况下  

    limit capacity 值一致

    Position 最大 值{下标(0开始)}capacity-1  

    写到哪  值是什么   0开始

    指针的值是 真实值+1  -->  将要写的位置  (最大到capacity值)

    xxxBuffer buffer = xxxBuffer.allocate(最大容量);

    Buffer.put(xx); 写入数据

    在读(read)模式的情况下

    Position 读到那值值是几,,但从0开始

    Limit 的值是position写模式的值(可读数据)

    重设缓冲区  切换到读模式

    Buffer.flip();

    Tip:

    package com.fsdm.nio.buffer;
    
    import java.nio.IntBuffer;
    
    /**
     * @author 房上的猫
     * @create 2018-07-03 17:11
     * @博客地址: https://www.cnblogs.com/lsy131479/
     * <p>
     * NIO 初探缓冲区
     **/
    
    public class BufferTest {
        public static void main(String[] args) {
            //创建缓冲区实例
            IntBuffer buffer = IntBuffer.allocate(10);
            System.out.println( "
    
    =====================写操作====================
    
    ");
            //监控各值
            System.out.println( "*************** 写模式初始值 ***************");
            System.out.println( "capacity=== » " +buffer.capacity());
            System.out.println( "position=== » " +buffer.position());
            System.out.println( "limit===» "+buffer. limit());
            //写入数据
            buffer.put(new int[]{1,1,1,2});
            //监控各值
            System.out.println( "*************** 写入值后 ***************");
            System.out.println( "capacity=== » " +buffer.capacity());
            System.out.println( "position=== » " +buffer.position());
            System.out.println( "limit===» "+buffer. limit());
            //重设缓冲区  切换到读模式
            buffer.flip();
            System.out.println( "
    
    ====================读操作=====================
    
    ");
            //监控各值
            System.out.println( "*************** 读模式初始值 ***************");
            System.out.println( "capacity=== » " +buffer.capacity());
            System.out.println( "position=== » " +buffer.position());
            System.out.println( "limit===» "+buffer. limit());
            //简单的读操作
            while (buffer.hasRemaining()){
                System.out.println(buffer.get());
                //监控各值
                System.out.println( "*************** 读取中 ***************");
                System.out.println( "capacity=== » " +buffer.capacity());
                System.out.println( "position=== » " +buffer.position());
                System.out.println( "limit===» "+buffer. limit());
            }
    
        }
    }

    二:channel 管道/通道

    作用:

    1. 基于buffer(缓冲区)对数据进行读写

    2. 管道是双向的,流是单向的

    3. 可以异步的读写

    常用实现类:

    网络传输:

    UDP:面向非连接,无脑流,效率高,性能好,非安全

    TCP:面向连接,效率低,性能差,安全

    1. FileChannel:从文件中读写数据

    2. DataGrarmChannel:通过UDP来读写网络中数据

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

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

    小Tip:

    package com.fsdm.nio.channel;
    
    import java.io.*;
    import java.nio.ByteBuffer;
    import java.nio.channels.Channel;
    import java.nio.channels.FileChannel;
    
    /**
     * @author 房上的猫
     * @create 2018-07-05 14:09
     * @博客地址: https://www.cnblogs.com/lsy131479/
     * <p>
     * 通过管道向文件中读写数据
     **/
    
    public class ChannelDemo {
        public static void main(String[] args) {
            //准备数据
            String[] strs = {"haha","hehe","heihei"};
            //写入  文件   输出流
            FileOutputStream fos=null;
            //准备管道
            FileChannel channel = null;
            try {
                 fos = new FileOutputStream("f:/a.txt");
                 //获取管道数据
                channel = fos.getChannel();
                //准备缓冲区
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                //将事先准备好的数据  写入缓冲区
                for (String str:strs) {
                    buffer.put(str.getBytes());
                    buffer.put("
    ".getBytes());
                }
                //将缓存区切换到读模式
                buffer.flip();
                //将缓冲区数据读取出来并写入磁盘  真正的写
                channel.write(buffer);
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                //回收资源
                try {
                    channel.close();
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }

    练习实例:(利用管道将a文件内容复制到b文件)

    package com.fsdm.nio.channel;
    
    import java.io.*;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    /**
     * @author 房上的猫
     * @create 2018-07-05 15:02
     * @博客地址: https://www.cnblogs.com/lsy131479/
     * <p>
     * a.txt   -->  b.txt
     **/
    
    public class ChannelBuffer {
        public static void main(String[] args) {
            //准备起始文件与终止文件
            File inFile = new File("f:/a.txt");
            File outFile = new File("f:/b.txt");
            //准备输入输出流
            FileInputStream fis = null;
            FileOutputStream fos = null;
            //准备双向管道
            FileChannel inChannel = null;
            FileChannel outChannel = null;
            try {
                //实例化各对象
                fis = new FileInputStream(inFile);
                fos = new FileOutputStream(outFile);
                inChannel = fis.getChannel();
                outChannel = fos.getChannel();
    
                //准备缓存区  (作为中转站)
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                int num = 0;
    
                //写入到缓冲区
                while ((num=inChannel.read(buffer))!=-1){
                    //转换缓冲区模式
                    buffer.flip();
                    //读取缓冲区数据并写入到磁盘
                    outChannel.write(buffer);
                    //清空缓冲区 方便下次读写
                    buffer.clear();
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    inChannel.close();
                    fis.close();
                    outChannel.close();
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }

    三:selector 选择器

     待后期单独总结

    高并发:NIO,线程

    Java 运行时数据区

    运行时都会被创建

    共享数据:

    heap

    方法区 method area

    私有数据:

    虚拟机栈 vm stack

    本地方法栈 native method stack

    程序计数器

    Xms:初始化容量

    Xmx:最大容量

    内存映射:

    就是把文件映射到电脑中的内存中,通过操作内存从而打到操作文件的目的

    内存中操作速度是最快的

     

    Java 中读取文件的几种方式:

    1. RandomAceessFile 随机读取,速度最慢

    2. FileInputStream 流的方式读取

    3. BufferReader 缓存的方式读取

    4. MappedByteBuffer 内存映射,速度最快

    内存映射的三种模式:MapMode

    1. READ_ONLY :对缓冲区的内存只读

    2. READ_WRITE :对缓冲区的内存读写

    3. PRIVATE :只会对缓冲区的内存进行修改,不会影响到真实的文件

    通常适用于数据的读取,一般不会进行对数据的写入

      内存映射读取文件与普通读取文件 效率对比:

    package com.fsdm.nio;
    
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.MappedByteBuffer;
    import java.nio.channels.FileChannel;
    
    /**
     * @author 房上的猫
     * @create 2018-07-05 18:00
     * @博客地址: https://www.cnblogs.com/lsy131479/
     * <p>
     * 内存映射
     **/
    
    public class MapperDemo {
        public static void main(String[] args) {
            FileChannel channel = null;
            RandomAccessFile file = null;
            try {
                file = new RandomAccessFile("e:/struts-2.3.31-lib.zip","rw");
                //获取通道
                channel = file.getChannel();
                //创建内存映射对象
                MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY,0,channel.size());
                byte[] bytes = new byte[1024];
                //获取文件大小
                long length = file.length();
                long begin = System.currentTimeMillis();
                ByteBuffer buffer2 = ByteBuffer.allocate(1024);
                for (int i=0;i<length;i+=1024){
                    if (length-i>1024){
                        buffer2=buffer.get(bytes);
                    }else{
                        buffer2=buffer.get(new byte[(int)(length-i)]);
                    }
                    buffer2.flip();
                    buffer2.clear();
                }
                long end = System.currentTimeMillis();
                System.out.println(end-begin);
                System.out.println("================");
                begin = System.currentTimeMillis();
                //普通读取缓冲区
                ByteBuffer buffer1 = ByteBuffer.allocate(1024);
                while (channel.read(buffer1)!=-1){
                    buffer1.flip();
                    buffer.clear();
                }
                 end = System.currentTimeMillis();
                System.out.println(end-begin);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    文件锁:

    FileLock :基于FlieChannel对文件提供锁的功能

    共享锁:

    共享读的操作

    读可以有多个,但是只能有一个人在写

    适合读取数据

    目的:是为了防止其他线程拿到独占锁

    独占锁:

    只能有一个读或写

    读写不能同时

    适合写数据

    Lock():

    阻塞

    无参默认是独占锁

    有参的可设置锁状态

    TyLock():

    非阻塞

    Tip 玩玩?

    package com.fsdm.nio.lock;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    import java.nio.channels.FileLock;
    import java.nio.channels.OverlappingFileLockException;
    
    /**
     * @author 房上的猫
     * @create 2018-07-05 18:15
     * @博客地址: https://www.cnblogs.com/lsy131479/
     * <p>
     * 锁
     **/
    
    public class LockDemo implements Runnable {
        static RandomAccessFile file = null;
        static FileChannel channel = null;
        static FileLock lock = null;
    
        public static void main(String[] args) {
            Thread thread = null;
            try {
    
                // lock = channel.lock(0L, Long.MAX_VALUE, true);
            } catch (Exception e) {
                e.printStackTrace();
            }
            for (int i = 0; i < 10; i++) {
                try {
                    file = new RandomAccessFile("f:/a.txt", "rw");
                    channel = file.getChannel();
                    if (i==0){
                        lock = channel.lock();
                       // lock = channel.lock(0L, Long.MAX_VALUE, true);
                        buffer.put("xx".getBytes());
    
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
                LockDemo lockDemo = new LockDemo();
                thread = new Thread(lockDemo, i+":");
                thread.start();
            }
            try {
                System.out.println(Thread.currentThread().getName()+(char)( channel.write(buffer)));
            } catch (IOException e) {
                e.printStackTrace();
            }
            ;
        }
       static   ByteBuffer buffer = ByteBuffer.allocate(1024);
        @Override
        public void run() {
            try {
                buffer =ByteBuffer.allocate(1024);
                buffer.put("xx".getBytes());
                System.out.println(Thread.currentThread().getName()+(char)( channel.write(buffer)));;
                //System.out.println(Thread.currentThread().getName()+(char)( channel.read(buffer)));;
            } catch (Exception e){
                e.printStackTrace();
            }
    
        }
    }
     
  • 相关阅读:
    python爬虫 -掘金
    python 爬取简书评论
    python爬取知乎评论
    python 爬取链家
    python爬虫获取下一页
    python正则找到字符串里面的数字
    faker切换user-agent
    python 爬虫可视化函数,可以先看看要爬取的数据是否存在
    acwing 471. 棋盘 解题记录
    ACWING 95 费解的开关 解题记录
  • 原文地址:https://www.cnblogs.com/lsy131479/p/9271787.html
Copyright © 2011-2022 走看看