返回 登录
0

解读Java的NIO

之前IO用的比较顺手,不过而最近一直听到nio,据说效率相当的高,决定好好研究下。

一、为什么要使用 NIO?
NIO 的创建目的是为了让 Java 程序员可以实现高速 I/O 而无需编写自定义的本机代码。NIO 将最耗时的 I/O 操作(即填充和提取缓冲区)转移回操作系统,因而可以极大地提高速度。

二、流与块的比较?
原来的 I/O 库(在 java.io.*中) 与 NIO 最重要的区别是数据打包和传输的方式。原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。
面向流的 I/O 系统一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。为流式数据创建过滤器非常容易。链接几个过滤器,以便每个过滤器只负责单个复杂处理机制的一部分,这样也是相对简单的。不利的一面是,面向流的 I/O 通常相当慢。
面向块的 I/O 系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。

三、简单代码带你入门

package com.lianggzone.file;
import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;
/**
 * NIO入门
 * @author LiangGzone
 * @version 2014-02-10
 */
public class NioDemo {
    public static void main(String[] args) throws Exception{
        String rFile = "D:/Test/NIO/demo.jpg";
        String wFile = "D:/Test/NIO/demo2.jpg";
        FileChannel fcin = new FileInputStream(rFile).getChannel();
        FileChannel fcout = new FileOutputStream(wFile).getChannel();
        ByteBuffer buff = ByteBuffer.allocate(1024);
        while(true){
            buff.clear();
            if((fcin.read(buff))==-1){
                break;
            }
            buff.flip();
            fcout.write(buff);
        }
    }
}

现在,我来说说这段代码吧!

1、通道
先说说通道的概念。通道是对原 I/O 包中的流的模拟。到任何目的地(或来自任何地方)的所有数据都必须通过一个 Channel 对象。一个Buffer 实质上是一个容器对象。发送给一个通道的所有对象都必须首先放到缓冲区中;同样地,从通道中读取的任何数据都要读到缓冲区中。Channel 是一个对象,可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较,通道就像是流。正如前面提到的,所有数据都通过 Buffer 对象来处理。您永远不会将字节直接写入通道中,相反,您是将数据写入包含一个或者多个字节的缓冲区。同样,您不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。

2、缓冲区
Buffer 是一个对象, 它包含一些要写入或者刚读出的数据。 在 NIO 中加入 Buffer 对象,体现了新库与原 I/O 的一个重要区别。在面向流的 I/O 中,您将数据直接写入或者将数据直接读到 Stream 对象中。在 NIO 库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在写入数据时,它是写入到缓冲区中的。任何时候访问 NIO 中的数据,您都是将它放到缓冲区中。缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。

3、状态变量
可以用三个值指定缓冲区在任意时刻的状态:position、limit、capacity。
position变量跟踪已经写了多少数据。更准确地说,它指定了下一个字节将放到数组的哪一个元素中。limit变量表示还有多少数据需要输出.capacity表明可以存储在缓冲区中的最大数据容量,即底层数组的大小.

4、buff.clear()
作用在于重设缓冲区。它的动作即将limit设置为与capacity相同、设置position为0。

5、buff.flip()
它的动作是将limit设置为当前position,将position设置为0。这样,当我们在读取到一定长度的数据的之后,然后通过这句话,修改缓冲区的limit为我们读取的长度,那么在再通过fcout.write(buff);即可获取到刚才读取的内容了。

6、循环体
循环的内容即与原IO相同,即文件的读与写。

三、代码还可以这样写
当然上面的代码只是简单的文件读写,NIO还有许多有用的功能,我们将在下文将讲解。这里,再附上一个文件读写的精简版。

package com.lianggzone.file;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
/**
 * NIO入门
 * @author LiangGzone
 * @version 2014-02-10
 */
public class NioDemo {
    public static void main(String[] args) throws Exception{
        String rFile = "D:/Test/NIO/demo.jpg";
        String wFile = "D:/Test/NIO/demo2.jpg";
        FileChannel fcin = new FileInputStream(rFile).getChannel();
        FileChannel fcout = new FileOutputStream(wFile).getChannel();
        //内部封装,调用这句话,直接即可实现文件复制
        fcin.transferTo(0, fcin.size(), fcout);
    }
}

学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:454297367 我们一起学Java!

评论