NIO

新IO(NIO)

一.概述

ava NIO ( New IO )是从 Java 1.4 版本开始引入的一个新的 IO API ,可以替代标准的 Java IO API 。NIO 与原来的 IO 有同样的作用和目的,但是使用的方式完全不同, NIO 支持面向缓冲区的、基于通道的 IO 操作。 NIO 将以更加高效的方式进行文件的读写操作.

两种流的对比
标准IO:

面向流,面向字节的流动,是单向的, 是阻塞的,无选择器 读 :输入流 写: 输出流

新IO:

面向缓冲区,基于通道操作,是非阻塞的,有选择器

二.通道(Channel)

1.概述

java.nio.channels 包定义的。 Channel 表示 IO 源与目标打开的连接。
Channel 类似于传统的“流”。只不过 Channel本身不能直接访问数据, Channel 只能与Buffer 进行交互。
简单的来说就是连接目标地点与源地点,但它不能存储数据

(1)获取通道方式1

FileChannel inChannel = in.getChannel();
FileChannel outChannel = out.getChannel();

(2)获取通道的方式2

通过FileChannel中的静态方法 open()可以打开一个通道

FileChannel inChannel = FileChannel.open(Paths.get("a.mp3"), StandardOpenOption.READ);
//StandardOpenOption.CREATE_NEW 文件不存在就创建,存在就报错
//StandardOpenOption.CREATE 文件不存在,就创建,存在 就覆盖
FileChannel outChanle = FileChannel.open(Paths.get("b.mp3"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);

获取通道的第三种方式

newByteChannel

2.通道中的文件传输

站在输入通道的角度复制文件

inChannel.transferTo(0,inChannel.size(),outChanle);

站在输出通道的角度复制文件

outChanle.transferFrom(inChannel,0,inChannel.size());

分配多个缓冲区

ByteBuffer byteBuffer1 = ByteBuffer.allocate(100);
ByteBuffer byteBuffer2 = ByteBuffer.allocate(1024 * 2);

ByteBuffer[] byteBuffers={byteBuffer1,byteBuffer2};//定义一个数组
inChannel.read(byteBuffers);//把通道中的数据,放到多个buffer中

聚集写入

        FileChannel outChannel = out.getChannel();
        outChannel.write(byteBuffers);
代码演示1(复制文件)
//通道中的文件传输
        FileChannel inChannel = FileChannel.open(Paths.get("歌曲串烧.mp3"), StandardOpenOption.READ);

        FileChannel outChanle = FileChannel.open(Paths.get("歌曲串烧2.mp3"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //站在输入通道的角度
        //inChannel.transferTo(0,inChannel.size(),outChanle);
        //站在输出通道的角度
        outChanle.transferFrom(inChannel,0,inChannel.size());
代码演示2(分散与聚集)
public static void main(String[] args) throws IOException {
        RandomAccessFile in = new RandomAccessFile("E:\\demo.txt", "rw");
        RandomAccessFile out = new RandomAccessFile("E:\\democopy.txt", "rw");
        //获取读取通道
        FileChannel inChannel = in.getChannel();
        //创建多个缓冲区
        ByteBuffer buffer1 = ByteBuffer.allocate(100);
        ByteBuffer buffer2 = ByteBuffer.allocate(1024);
        //分散读取到多个缓冲区中
        ByteBuffer[] byteBuffers=new ByteBuffer[]{buffer1,buffer2};//把多个缓冲区放到一个大的数组中
        long read = inChannel.read(byteBuffers);//把这个大的缓冲区传进去
        
        //当然我们可以看看,每个缓冲区中读入的数据
        //byteBuffers[0].flip(); //切换到读取模式 看一下第一个缓冲区,读入的100个字节
        //byte[] array = byteBuffers[0].array();//把ByteBuffer转换成字节数组
        //String s = new String(array, 0, byteBuffers[0].limit());
        //System.out.println(s);

        //把每个缓冲区,切换到读取模式
        for (ByteBuffer buffer : byteBuffers) {
            buffer.flip();
        }
        //聚集写入
        FileChannel outChannel = out.getChannel();
        outChannel.write(byteBuffers);

        //释放资源
        inChannel.close();
        outChannel.close();
    }

三.缓冲区(buffer)

1.概述

一个用于特定基本数据类型的容器。由 java.nio 包定义的,所有缓冲区都是 Buffer 抽象类的子类。
Java NIO 中的 Buffer 主要用于与 NIO 通道进行交互,数据是从通道读入缓冲区,从缓冲区写入通道中的。
简单的来说就是进行数据的处理,底层是数组,作用是用来存储数据

2.buffer常用的子类

ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer

上述 Buffer 类 他们都采用相似的方法进行管理数据,只是各自
管理的数据类型不同而已。其中Bytebuffer最常用。

3.buffer的重要属性(以ByteBuffer为例)

capacity:缓冲区的容量,一旦指定容量后不能更改

ByteBuffer byteBuffer = ByteBuffer.allocate(10);//指定一个容量为10的缓冲区

limit:界限,从limit往后的数据不能读写

int limit = byteBuffer.limit();//返回当前界限值

posotion:位置,文件指针,从posotion开始可以读数据

int position = byteBuffer.position();//返回当前指针位置

put():往容器中放数据

bytebuffer.put(str.getBytes());

flip():读取缓冲区的数据,切换成读取模式

bytebuffer.flip();

get():读取数据

bytebuffer.get()
//读取俩个字节
byte[] bytes = new byte[byteBuffer.limit()];
byteBuffer.get(bytes,0,2);

rewind():可重复读取

bytebuffer.rewind()

clear():清空缓冲区,并不是把缓冲区的字节数据清除掉,而是把指针设置到最初状态

bytebuffer.clear();

mark():可以标记当前的position位置

bytebuffer.mark();

reset():回到上一次标记position的位置

bytebuffer.reset();

hasRemaining():查看还有多少可读数据

 if(byteBuffer.hasRemaining()){
 System.out.println(byteBuffer.remaining()); //remaining()还有多少可读取数据
}

针对基本类型(布尔类型除外)都有相应的缓冲区

4.缓冲区分类

(1)非直接缓冲区allocatr(1024)

将缓冲区建立在jvm的内存中

ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
(2)直接缓冲区allocatrDirect(1024):

将缓冲区建立在物理内存中,效率高,比较耗费资源

ByteBuffer byteBuffer1 = ByteBuffer.allocateDirect(1024);

5.复制文件

(1)采用NIO非直接缓冲区复制本地文件
public static void main(String[] args) throws IOException {
        //创建文件输入输入流
        FileInputStream in = new FileInputStream("a1.mp3");
        FileOutputStream out = new FileOutputStream("a2.mp3");
        //文件输入输入流的getChannel()方法获取通道
        FileChannel inChannel = in.getChannel();
        FileChannel outChannel = out.getChannel();
        //获取非直接缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //将通道中的数据放入到缓冲区中
        while (inChannel.read(byteBuffer) != -1) {
            //切换读取数据的模式
            byteBuffer.flip();
            //将缓冲区中的数据写入通道中
            outChannel.write(byteBuffer);
            //清空缓冲区
            byteBuffer.clear();
        }
        //释放资源
        in.close();
        out.close();
        inChannel.close();
        outChannel.close();
    }
(2)采用直接缓冲区复制文件
public static void main(String[] args) throws IOException {
        //通过文件通道的静态方法,打开读写通道
        //参1:通过Paths获取源文件的路径
        //参2:操作模式 StandardOpenOption.READ 读取模式
        //打开读取文件的通道
        FileChannel in = FileChannel.open(Paths.get("a1.mp3"), StandardOpenOption.READ);
        //打开写入的通道 模式要读还要写  StandardOpenOption.CREATE 意思是文件不存在就创建,如果存在就覆盖
        //StandardOpenOption.CREATE_NEW 意思是文件不存在就创建,如果存在就报错
        FileChannel out = FileChannel.open(Paths.get("a2.mp3"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //操作内存映射文件(也就是这个缓冲区在物理内存中)
        MappedByteBuffer inByteBuffer = in.map(FileChannel.MapMode.READ_ONLY, 0, in.size());
        MappedByteBuffer outByteBuffer = out.map(FileChannel.MapMode.READ_WRITE, 0, in.size());
        //直接对缓冲区进行读写操作
        byte[] bytes = new byte[inByteBuffer.limit()];
     	inByteBuffer.get(bytes);
        outByteBuffer.put(bytes);
        //释放资源
        in.close();
        out.close();
    }

files类复制文件

方式一:

       Files.copy(new FileInputStream("demo.txt"), Paths.get("demo55.txt"), StandardCopyOption.REPLACE_EXISTING);

方式二:

        Files.copy(Paths.get("demo55.txt"),new FileOutputStream("demo66.txt"));

方式三:

        Files.copy(Paths.get("demo.txt"), Paths.get("demo77.txt"), StandardCopyOption.REPLACE_EXISTING);

注意:StandardCopyOption.REPLACE_EXISTING 是可选参数,复制文件,如果文件存在就替换,如果不写这个参数,就是文件存在,就报错,不会覆盖

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值