java nio利用通道和缓冲器提高I/O速度

JDK 1.4的java.nio.*包中引入了新的JavaI/0类库,其目的在于提高速度。实际上,旧的I/0 包已经使用nio重新实现过,以便充分利用这种速度提高,因此,即使我们不显式地用nio编写代码,也能从中受益。速度的提高在文件I/0和网络I/0中都有可能发生,我们在这里只讨论前者。

速度的提高来自于所使用的结构更接近千操作系统执行I/O的方式:通道和缓冲器。我们可以把它想像成一个煤矿,通道是一个包含煤层(数据)的矿藏,而缓冲器则是派送到矿藏的卡车。 卡车载满煤炭而归, 我们再从卡车上获得煤炭。 也就是说,我们井没有直接和通道交互,我们只是和缓冲器交互,并把缓冲器派送到通道。通道要么从缓冲器获得数据,要么向缓冲器发送数据。

对于文件的读写相当于我们在文件中打开一个通道,将数据通过缓冲器从通道中输入或者输出。

唯一直接与通道交互的缓冲器是ByteBuffer–也就是说,可以存储未加工字节的缓冲器 。当我们查询JDK文档中的java.nio.ByteBuffer时,会发现它是相当基础的类:通过告知分配多少存储空间来创建一个ByteBuffer对象,并且还有一个方法选择集,用千以原始的字节形式或基本数据类型输出和读取数据。 但是,没办法输出或读取对象,即使是字符串对象也不行。 这种处理虽然很低级,但却正好,因为这是大多数操作系统中更有效的映射方式。.

旧 I/0类库中有三个类被修改了,用以产生FileChannel 。这三个被修改的类是FilelnputStream、FileOutputStream以及用于既读又写的RandomAccessFile。注意这些是字节操纵流,与低层的nio性质一致。Reader和Writer这种宇符模式类不能用千产生通道;但是 java.nio.channels.Cbannels类提供了实用方法,用以在通道中产生Reader和Writer。

下面的简单实例演示了上面三种类型的流,用以产生可写的、 可读可写的及可读的通道:

package com.zzy.io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class GetChannel {
    private static final int BSIZE = 1024;

    public static void main(String[] args) throws Exception{
        //写文件
        //获取一个文件的通道
        FileChannel fc = new FileOutputStream("data.txt").getChannel();
        //利用wrap()方法将已存在的字节数组包装到缓冲器ByteBuffer中,再通过通道写入文件
        fc.write(ByteBuffer.wrap("data text".getBytes()));
        fc.close();
        fc = new RandomAccessFile("data.txt", "rw").getChannel();
        //将通道移动到文件末尾
        fc.position(fc.size());
        fc.write(ByteBuffer.wrap("end text".getBytes()));
        fc.close();

        //读文件
        fc = new FileInputStream("data.txt").getChannel();
        //移动到文件倒数第三个字节
        fc.position(fc.size()-3);
        //使用静态的allocate()方法来分配ByteBuffer的大小
        ByteBuffer buffer = ByteBuffer.allocate(BSIZE);
        fc.read(buffer);
        //执行flip()告诉缓冲器做好准备接收数据
        buffer.flip();
        while ((buffer.hasRemaining())){
            System.out.println((char) buffer.get());
        }
        //如果继续传输数据,记得清空缓冲器
        buffer.clear();
        fc.close();

    }
}

文件内容:
在这里插入图片描述
输出:在这里插入图片描述

从第二张输出图中我们可以看到确实是从文件中倒数第三个字符开始输出的。

另外复制文件我们可以利用一个文件的通道与另一个文件的通道直接连接,用特殊方法transferTo()和transferFrom(),这样真的很简便。

public class Transfer {
    public static void main(String[] args) throws Exception{
        FileChannel in = new FileInputStream("data.txt").getChannel();
        FileChannel out = new FileOutputStream("new.txt").getChannel();
        //两种方式皆可以复制文件
        //in.transferTo(0,in.size(),out);
        out.transferFrom(in,0,in.size());

    }
}
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页