美文网首页
Java I/O系统

Java I/O系统

作者: DaemonXiao | 来源:发表于2019-03-22 17:55 被阅读0次

    1 输入和输出

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

    1.1 InputStream类型

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

    • FileInputStream:用于从文件中读取信息,构造器参数是字符串,表示文件名、文件或者FileDescriptor对象。
    //可以使用字符串类型的文件名来创建一个输入流对象来读取文件
    InputStream fin = new FileInputStream("C:\java\hello.class");
    //也可以使用一个文件对象来创建一个输入流对象来读取文件
    File f = new File("C:\java\hello.class");
    InputStream fin2 = new FileInputStream(f);
    

    1.2 OutputStream类型

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

    • FileOutoutStream:用于将信息写至文件,构造器参数是字符串,表示文件名、文件或者FileDescriptor对象。如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件。
    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() 。
    四个核心属性:

    • capacity:表示缓冲区中最大存储数据的容量,一旦声明不能改变,即数组大小。
    • limit:缓冲区中可以操作数据的大小。(limit后面的数据不能进行读写)
    • position:表示缓冲区正在操作的位置。
    • mark:标记,表示记录当前position位置,可以通过reset() 回到刚才记录位置
      position <= limit <= capacity
        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();
     }
    

    相关文章

      网友评论

          本文标题:Java I/O系统

          本文链接:https://www.haomeiwen.com/subject/xwmlvqtx.html