Java I/O系统

2019-03-22  本文已影响0人  DaemonXiao

1 输入和输出

Java类库中的I/O类分成输入和输出两部分,通过叠合多个对象来提供所期望的功能(装饰者设计模式)。

1.1 InputStream类型

InputStream的作用是用来表示那些从不同数据源产生输入的类。这些数据源包括:字节数组、String对象、文件、管道、一个由其他种类的流组成的序列、其他数据源等。
常用的类:

//可以使用字符串类型的文件名来创建一个输入流对象来读取文件
InputStream fin = new FileInputStream("C:\java\hello.class");
//也可以使用一个文件对象来创建一个输入流对象来读取文件
File f = new File("C:\java\hello.class");
InputStream fin2 = new FileInputStream(f);

1.2 OutputStream类型

该类别的类决定了输出所要去的目标:字节数组、文件或者管道。
常用的类:

import java.io.*;
 
public class fileStreamTest {
    public static void main(String args[]) {
        try {
            byte bWrite[] = { 11, 21, 3, 40, 5 };
            OutputStream os = new FileOutputStream("test.txt");
            for (int x = 0; x < bWrite.length; x++) {
                os.write(bWrite[x]); // writes the bytes
            }
            os.close();
 
            InputStream is = new FileInputStream("test.txt");
            int size = is.available();
 
            for (int i = 0; i < size; i++) {
                System.out.print((char) is.read() + "  ");
            }
            is.close();
        } catch (IOException e) {
            System.out.print("Exception");
        }
    }
}

2 Reader和Writer

Java 1.1对基本的I/O流类库进行了重大的修改,Reader和Writer这两个类不是用来替代上述的InputStream和OutputStream的类。它们面向的对象不同,Stream在以面向字节形式的I/O中仍然可以提供极有价值的功能,Reader和Writer则提供兼容Unicode与面向字符I/O功能。
有时我们必须把来自于“字节”层次结构中的类和“字符”层次结构中的类结合起来使用,为了实现这个目的,要用到适配器(adapter)类:InputStreamWriter和OutputStreamWriter。
设计Reader和Writer继承层次结构主要是为了国际化。老的I/O流继承层次结构仅支持8位字节流,并且不能很好地处理16位的Unicode字符。由于Unicode用于字符国际化,所以添加Reader和Writer继承层次的结构就是为了在所有的I/O操作中都支持Unicode。另外,新类库的设计使得它的操作比旧类库更快。

3 NIO

3.1 什么是NIO?

JDK 1.4的java.nio.*包中引入了新的Java I/O类库,其目的在于提高速度。实际上,旧的I/O包已经用nio重新实现过,以便充分利用这种速度提高,因此,即使我们不显式地使用nio编程,也能从中受益。
速度的提高来自于所使用的结构更接近于操作系统执行I/O的方式:通道和缓冲器。
NIO主要有三大核心部分:Channel,Buffer,Selector。传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer进行。数据总是从通道读取到缓冲区,或者从缓冲区写入到通道中。Selector用于监听多个通道的事件,因此,单个线程可以监听多个数据通道。

    public void method(){
        RandomAccessFile aFile = null;
        try{
            aFile = new RandomAccessFile("F:\\发票与回单\\抬头与税务号.txt","rw");
            FileChannel fileChannel = aFile.getChannel();
            ByteBuffer buf = ByteBuffer.allocate(1024);
            int bytesRead = fileChannel.read(buf);
            System.out.println(bytesRead);
            while(bytesRead != -1)
            {
                buf.flip();
                while(buf.hasRemaining())
                {
                    System.out.print((char)buf.get());
                }
                buf.compact();
                bytesRead = fileChannel.read(buf);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally{
            try{
                if(aFile != null){
                    aFile.close();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }

3.2 主要区别

3.3 缓冲区

在java nio中负责数据存取。缓冲区是数组。根据数据类型的不同,提供了响应的缓冲区:ByteBuffer, CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer, DoubleBuffer。通过allocate() 获取缓冲区,主要方法为put() 和get() 。
四个核心属性:

    public void bufferTest() {

        //1. 分配一个指定大小的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);

        //2. 调用put方法存入数据
        String ss = "7777";
        buf.put(ss.getBytes());

        //3. 切换取数据 flip()
        buf.flip();

        //4. 利用get方法读取
        byte[] dst = new byte[buf.limit()];
        buf.get(dst);
        System.out.println(new String(dst));

        //5. rewind方法可重复读数据
        buf.rewind();

        //6. 清空缓冲区,但是缓冲区的数据易燃存在,只是指针回到初始,数据处于“被遗忘”状态。
        buf.clear();

    }

非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在JVM内存中
直接缓冲区:通过allocateDirect()方法分配直接内存,将缓冲区建立在物理内存中,可以提高效率。
通过isDirect() 方法判断是否是直接缓冲区。


直接缓冲区

3.4 通道

通道用于源节点与目标节点的链接,需要配合缓冲区进行传输。通道的主要实现类:FileChannel, SocketChannel, ServerSocketChannel, DatagramChannel。
获取方式:

  1. getChannel()。
  2. 在 JDK 1.7中NIO.2 针对各个通道提供了静态方法open()。
  3. 在 JDK 1.7中NIO.2的Files工具类的newByteChannel()。
public void channelTest() throws IOException {
        FileInputStream fis = new FileInputStream("1.jpg");
        FileOutputStream fos = new FileOutputStream("2.jpg");

        //1. 获取通道
        FileChannel inChannel = fis.getChannel();
        FileChannel outChannel = fos.getChannel();

        //2. 分配指定大小缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);

        //3. 将通道数据存入缓冲区
        while (inChannel.read(buf) != -1) {
            buf.flip();
            outChannel.write(buf);
            buf.clear();
        }

        outChannel.close();
        inChannel.close();
        fos.close();
        fis.close();
 }
上一篇 下一篇

猜你喜欢

热点阅读