专栏首页个人随笔Java持久化之 -- 傲娇的NIO

Java持久化之 -- 傲娇的NIO

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:

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:

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文件)

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();
        }

    }
}
 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 房上的猫:人机猜拳项目

    1.首先定义成员变量: int select1;// 人 选择 int select2;// 角色 选择 String choice1;...

    房上的猫
  • Java 持久化之 -- IO 全面整理(看了绝不后悔)

    IO包括输入流和输出流,输入流指的是将数据以字符或者字节形式读取到内存 分为字符输入流和字符输入流

    房上的猫
  • 房上的猫:吃货联盟项目

    一.首先先定义部分成员变量: String[] name = new String[4];// 订餐人 String[] greens = new St...

    房上的猫
  • NIO前言:一、NIO与IO的区别二、通道和缓冲区三、NIO的网络通信总结:

    所谓NIO,就是New IO的缩写。是从JDK 1.4开始引入的全新的IO API。NIO将以更高效的方式进行文件的读写操作,可完全代替传统的IO API使用。...

    贪挽懒月
  • NIO

    用户5927264
  • Java必考面试题「版本特性」

    Java 8用默认方法与静态方法这两个新概念来扩展接口的声明。与传统的接口又有些不一样,它允许在已有的接口中添加新方法,而同时又保持了与旧版本代码的兼容性。

    Java3y
  • 一文看透java8新特性

    毫无疑问,Java 8发行版是自Java 5(发行于2004,已经过了相当一段时间了)以来最具革命性的版本。Java 8 为Java语言、编译器、类库、开发工具...

    好好学java
  • 完整剖析SpringAOP的自调用

    spring全家桶帮助java web开发者节省了很多开发量,提升了效率。但是因为屏蔽了很多细节,导致很多开发者只知其然,不知其所以然,本文就是分析下使用spr...

    黄泽杰
  • 完整剖析SpringAOP的自调用

    spring全家桶帮助java web开发者节省了很多开发量,提升了效率。但是因为屏蔽了很多细节,导致很多开发者只知其然,不知其所以然,本文就是分析下使用spr...

    方丈的寺院
  • ASP.NET中各命名空间及作用

    System                            包含了基础类,用于定义类型/数组/字符串/事件/事件处理程序/异常 处理 /接口/数据类型转...

    DougWang

扫码关注云+社区

领取腾讯云代金券