前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java持久化之 -- 傲娇的NIO

Java持久化之 -- 傲娇的NIO

作者头像
房上的猫
发布2019-01-24 11:05:07
5130
发布2019-01-24 11:05:07
举报
文章被收录于专栏:个人随笔

NIO:

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

所在包:java.nio

执行流程:

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

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

三个组件:

1. channel   通道

2. Buffer   缓冲区

3. Selector   选择器

NIO和IO 的区别

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:

代码语言:javascript
复制
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( "\n\n=====================写操作====================\n\n");
        //监控各值
        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( "\n\n====================读操作=====================\n\n");
        //监控各值
        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:

代码语言:javascript
复制
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("\n".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文件)

代码语言:javascript
复制
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:最大容量

内存映射:

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

内存中操作速度是最快的

代码语言:javascript
复制

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

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

2. FileInputStream 流的方式读取

3. BufferReader 缓存的方式读取

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

内存映射的三种模式:MapMode

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

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

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

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

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

代码语言:javascript
复制
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 玩玩?

代码语言:javascript
复制
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();
        }

    }
}
 
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-07-06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • NIO:
  • 执行流程:
  • 三个组件:
  • NIO和IO 的区别
  • 一:buffer 缓冲区
    • 读写两种模式
      • 三个重要的值:
        • 在写(write)模式的情况下  
        • 在读(read)模式的情况下
        • 小Tip:
    • 二:channel 管道/通道
      • 作用:
        • 常用实现类:
        • 三:selector 选择器
        • Java 运行时数据区
        • 内存映射:
          • Java 中读取文件的几种方式:
            • 内存映射的三种模式:MapMode
            • 文件锁:
              • 共享锁:
                • 独占锁:
                  • Lock():
                    • TyLock():
                      • 小Tip 玩玩?:
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档