IO与NIO

Posted 864466244qq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IO与NIO相关的知识,希望对你有一定的参考价值。

IO

IO概念:

Java IO

Java IO java的输入系统,不管我们编写任何种语言,都难免输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,还要考虑的因素特别多,比如我们要考虑哪种媒介进行IO(文件,控制台,网络),还要考虑具体的通信方式,(顺序,随机,二进制,按字,按行等等)Java类库设计者设计大量的类来攻克,这些类就存在java.IO包中。

Java IO中,流是一个核心的概念。流从概念上来说是一个连续的数据流。你既可以从流中读取数据,也可以往流中写数据。流与数据源或者数据流向的媒介相关联。在Java IO中流既可以是字节流(以字节为单位进行读写),也可以是字符流(以字符为单位进行读写)。

Java IO类型

虽然java IO类库庞大,但总体来说,框架还是很清楚的,从是读媒介的维度来看,java IO还可以分为:

  1. 输入流:InputStreamReader
  2. 输出流:OutputStreamWriter

处理的流类型维度来看,java IO 又可分为:

  1. 字节流:InputStreamOutputStream
  2. 字符流:ReaderWriter

Java IO的分类图:

 技术分享图片

 

Java IO:网络媒介

关于Java IO面向网络媒介的操作即Java 网络编程,其核心是Socket,同磁盘操作一样,java网络编程对应着两套API,即Java IO和Java NIO

Java IO:BufferedInputStream和BufferedOutputStream

BufferedInputStream顾名思义,就是在对流进行写入时提供一个buffer来提

IO效率。在进行磁盘或网络IO时,原始的InputStream对数据读取的过程都

是一个字节一个字节操作的,而BufferedInputStream在其内部提供了一个,

buffer在读数据时,会一次读取一大块数据到buffer中,这样比单字节的操作效率

要高的多,特别是进程磁盘IO和对大量数据进行读写的时候。

Buffer:

 //创建输入和输出流

        Reader reader=null;

        Writer writer=null;

        BufferedReader  br=null;

        BufferedWriter bw=null;

        try {

            writer=new FileWriter("e:/a.txt",true);

            bw=new BufferedWriter(writer); //封装

            bw.write("大家辛苦了!");

            bw.newLine();  //换行

            bw.write("大家别眨眼!");

            bw.flush();

            bw.write("大家别眨眼22");

            bw.write("大家别眨眼33");

            bw.close();

            writer.close();  //如果不关闭  后续两句话没法获取

            //读取

            reader=new FileReader("e:/a.txt");

            br=new BufferedReader(reader);//封装

            String line=null;

            StringBuffer sb=new StringBuffer();

            while ((line=br.readLine())!=null){

                sb.append(line);

            }

            System.out.println(sb.toString());

        } catch (Exception e) {

            e.printStackTrace();

        }finally {

            try {

                br.close();

                reader.close();

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }

序列化与反序列化:

**

 * 序列化和反序列化

 * ObjectInputStream  ObjectOutputStream

 */

public class ObjectDemo {

 

    static Scanner  input=new Scanner(System.in);

    //创建需要的输入和输出流对象

    static   InputStream inputStream=null;

    static  OutputStream outputStream=null;

    static ObjectInputStream objectInputStream=null;

    static ObjectOutputStream  objectOutputStream=null;

 

    public static void main(String[] args) {

         //注册   序列化

        //register();

        //登录  反序列化

        login();

    }

 

    //注册

    private static void register()  {

        User user=new User();

        System.out.println("请输入您的用户名:");

        user.setUserName(input.next());

        System.out.println("请输入您的密码:");

        user.setPassword(input.next());

 

        try {

            outputStream=new FileOutputStream("e:/user.txt");

            objectOutputStream=new ObjectOutputStream(outputStream);

            //把对象输出到文件中

            objectOutputStream.writeObject(user);

        } catch (Exception e) {

            e.printStackTrace();

        }finally {

            try {

                objectOutputStream.close();

                outputStream.close();

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }

 

 

    //登录

    private static void login() {

        try {

            inputStream=new FileInputStream("e:/user.txt");

            objectInputStream=new ObjectInputStream(inputStream);

            //读取对象

            User user= (User) objectInputStream.readObject();

            System.out.println(user);

        } catch (Exception e) {

            e.printStackTrace();

        }finally {

            try {

                objectInputStream.close();

                inputStream.close();

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

}

 

 

 

User类:

public class User implements  Serializable{

 

 

    private  String  userName;

    private  String  password;

 

    public String getUserName() {

        return userName;

    }

 

    public void setUserName(String userName) {

        this.userName = userName;

    }

 

    public String getPassword() {

        return password;

    }

 

    public void setPassword(String password) {

        this.password = password;

    }

 

    public User(String userName, String password) {

        this.userName = userName;

        this.password = password;

    }

 

    public User() {

    }

 

    @Override

    public String toString() {

        return "User{" +

                "userName=‘" + userName + ‘‘‘ +

                ", password=‘" + password + ‘‘‘ +

                ‘}‘;

    }

NIO

 Java  io 回顾

Java 标准 IO 类库是 io 面向对象的一种抽象。基于本地方法的底层实现,我们无须关注底层实现。InputStreamOutputStream( 字节流 ) :一次传送一个字节。 ReaderWriter( 字符流 ) :一次一个字符。

 

nio 简介

nio 是 java New IO 的简称,在 jdk1.4 里提供的新 api 。 Sun 官方标榜的特性如下:

 

   为所有的原始类型提供 (Buffer) 缓存支持。

   字符集编码解码解决方案。

   Channel :一个新的原始 I/O 抽象。

   支持锁和内存映射文件的文件访问接口。

   提供多路 (non-bloking) 非阻塞式的高伸缩性网络 I/O 。

本文将围绕这几个特性进行学习和介绍。

Buffer&Chanel

Channel 和 buffer 是 NIO 是两个最基本的数据类型抽象。

Buffer:

     是一块连续的内存块。

    NIO 数据读或写的中转地。

Channel:

     数据的源头或者数据的目的地

    用于向 buffer 提供数据或者读取 buffer 数据 ,buffer 对象的唯一接口。

异步 I/O 支持

 

channel和buffer关系图:

 技术分享图片

 

NIO的新特性

总的来说java 中的IO 和NIO的区别主要有3点:

IO是面向流的,NIO是面向缓冲的;

IO是阻塞的,NIO是非阻塞的;

IO是单线程的,NIO 是通过选择器来模拟多线程的;

NIO在基础的IO流上发展处新的特点,分别是:内存映射技术,字符及编码,非阻塞I/O和文件锁定。下面我们分别就这些技术做一些说明。

内存映射

这个功能主要是为了提高大文件的读写速度而设计的。内存映射文件(memory-mappedfile)能让你创建和修改那些大到无法读入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问了。将文件的一段区域映射到内存中,比传统的文件处理速度要快很多。内存映射文件它虽然最终也是要从磁盘读取数据,但是它并不需要将数据读取到OS内核缓冲区,而是直接将进程的用户私有地址空间中的一部分区域与文件对象建立起映射关系,就好像直接从内存中读、写文件一样,速度当然快了。

NIO中内存映射主要用到以下两个类:

1.java.nio.MappedByteBuffer

2.java.nio.channels.FileChannel

 

NIO增加新功能

  1. 有选择器

选择器(Selectors

     Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来选择通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

 

  1. 可以只用正则表达式
  2. 支持内存映射
  3. 支持文件锁

 

Buffer 缓冲区

本质是一个写入数据,并且从中读取数据的内存!

存储的是相同数据类型的值

1.position:写入或读取的是数据的当前指针,最大值:capacity-1

2.Limit:有多少数据可以写或者可以读

 write模式下,我们limitcapacity的值一致

read模式下limitwrite模式下的position的值一致

read模式下代表的就是最大的读取量(写多少读多少)

3.Capacity:缓冲区的最大容量

 

Buffer
传统的I/O不断的浪费对象资源(通常是String)。新I/O通过使用Buffer读写数据避免了资源浪费。Buffer对象是线性的,有序的数据集合,它根据其类别只包含唯一的数据类型。


java.nio.Buffer 类描述
java.nio.ByteBuffer 包含字节类型。 可以从ReadableByteChannel中读在 WritableByteChannel中写
java.nio.MappedByteBuffer 包含字节类型,直接在内存某一区域映射
java.nio.CharBuffer 包含字符类型,不能写入通道
java.nio.DoubleBuffer 包含double类型,不能写入通道
java.nio.FloatBuffer 包含float类型
java.nio.IntBuffer 包含int类型
java.nio.LongBuffer 包含long类型
java.nio.ShortBuffer 包含short类型


可以通过调用allocate(int capacity)方法或者allocateDirect(int capacity)方法分配一个Buffer。特别的,你可以创建MappedBytesBuffer通过调用FileChannel.map(int mode,long position,int size)。直接(directbuffer在内存中分配一段连续的块并使用本地访问方法读写数据。非直接(nondirect)buffer通过使用Java中的数组访问代码读写数据。有时候必须使用非直接缓冲例如使用任何的wrap方法(如ByteBuffer.wrap(byte[]))在Java数组基础上创建buffer

 

字符编码


ByteBuffer中存放数据涉及到两个问题:字节的顺序和字符转换。ByteBuffer内部通过ByteOrder类处理了字节顺序问题,但是并没有处理字符转换。事实上,ByteBuffer没有提供方法读写String


Java.nio.charset.Charset处理了字符转换问题。它通过构造CharsetEncoderCharsetDecoder将字符序列转换成字节和逆转换。

 

通道(Channel)


你可能注意到现有的java.io类中没有一个能够读写Buffer类型,所以NIO中提供了Channel类来读写Buffer。通道可以认为是一种连接,可以是到特定设备,程序或者是网络的连接

 















以上是关于IO与NIO的主要内容,如果未能解决你的问题,请参考以下文章

java中的IO与NIO

Java NIO:IO与NIO的区别

[NIO] IO与NIO

Java中nio与io的区别与联系

IO与NIO的区别

Java NIO:IO与NIO的区别