`
frank-liu
  • 浏览: 1666475 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java I/O总结

阅读更多

简介

    我们常和io打交道,这个类族里面牵涉到的类很多,经常让人觉得比较迷茫。在使用的时候也不容易找到合适的类来完成自己的任务。这里结合前面一篇讨论java io和设计模式相关的文章针对java io里几个主要io类型的类做了一个总结。通过对类的结构和关系的理顺,我们可以更好的使用现有io相关的类,在以后有必要的时候也可以去定制自己所需要的功能。

总体说明 

    在详细讨论每个具体类别之前,我们可以先回想一下自己以前使用java io的时候常碰到的一些用法。比如说我们在要读取一个文件的时候,我们常使用如下的形式:

InputStream in = new BufferedInputStream(
                          new FileInputStream("test.txt"));

    我们通过FileInputStream可以直接打开文件,如果我们想增加一些新的特性,我们用BufferedInputStream来包装了它一把。比较有意思的是它居然也是一个InputStream类型,还可以把它当成一个基类来使。这种用法的核心根源在于它采用的是decorator的设计模式。在我的这篇文章里对它的由来做了一个详细的分析。在一个decorator模式描述的场景里我们有一系列的核心类,相当于提供了若干基本的功能。同时,我们也有一系列的包装类,它是对现有类功能的增强,但是它不是一个独立的类,需要将一个核心类作为参数给它包装。我们以java io里的InputStream类族为例,它的主要类图结构如下图:

 

 

    我们可以发现真正要扩展功能的点是都继承自类FilterInputStream。它只是一个简单的类代理,在它内部有一个指向InputStream类型的成员变量:

protected volatile InputStream in;

   它的构造函数也只是相当于将一个InputStream类型的对象引入进来:

protected FilterInputStream(InputStream in) {
        this.in = in;
    }

    从这里只看到这个类其实什么都没干,它只是做一个把功能代理给另外一个类做的示范。具体添加扩展功能的都是它的子类,我们就以它的子类BufferedInputStream为例来看看它是怎么增强功能的。

    前面那部分的代码将定义的成员变量以及方法声明为protected,这说明这些继承它的子类是可以访问到这个InputStream成员变量的。我们以read方法为例看看它具体的增强:

public synchronized int read() throws IOException {
        if (pos >= count) {
            fill();
            if (pos >= count)
                return -1;
        }
        return getBufIfOpen()[pos++] & 0xff;
    }

    这个方法只是读取下一个字节,但是它内部采用了一个字节串作为缓冲。在读取的时候fill()方法实际上在填充整体的缓冲区。fill方法的实现虽然比较繁琐:

private void fill() throws IOException {
        byte[] buffer = getBufIfOpen();
        if (markpos < 0)
            pos = 0;            /* no mark: throw away the buffer */
        else if (pos >= buffer.length)  /* no room left in buffer */
            if (markpos > 0) {  /* can throw away early part of the buffer */
                int sz = pos - markpos;
                System.arraycopy(buffer, markpos, buffer, 0, sz);
                pos = sz;
                markpos = 0;
            } else if (buffer.length >= marklimit) {
                markpos = -1;   /* buffer got too big, invalidate mark */
                pos = 0;        /* drop buffer contents */
            } else {            /* grow buffer */
                int nsz = pos * 2;
                if (nsz > marklimit)
                    nsz = marklimit;
                byte nbuf[] = new byte[nsz];
                System.arraycopy(buffer, 0, nbuf, 0, pos);
                if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
                    // Can't replace buf if there was an async close.
                    // Note: This would need to be changed if fill()
                    // is ever made accessible to multiple threads.
                    // But for now, the only way CAS can fail is via close.
                    // assert buf == null;
                    throw new IOException("Stream closed");
                }
                buffer = nbuf;
            }
        count = pos;
        int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
        if (n > 0)
            count = n + pos;
    }

     但是它本质上是一个填充缓冲区数组的操作,同时通过int n = getInIfOpen().read(buffer, pos, buffer.length - pos);语句使用InputStream做了一个预读取操作。

    我们前面举这个示例并不是要对它所有的代码做一个分析,而是针对decorator具体功能的实现做一个跟踪。在扩展类里,无非做的就是一个调用被包装对象的方法,同时将自己附加的功能也添加上去。相信有了这么一个说明,我们对它的具体实现理解更加深刻,在后面部分的说明也更加容易理解。

     在java io里,InputStream, OutputStream, Reader, Writer的类结构都采用了decorator模式。

Stream

    InputStream和OutputStream面向的是通用的字节流访问方式,对于文件读取和数据传输都可以使用。

    下图是InputStream的类结构:

 

     FilterInputStream就是里面包装类的基类,所有需要增强InputStream效果的类实现可以继承它。这里已经包含的有BufferedInputStream, CheckedInputStream等。我们如果要增加新功能的话也可以按照BufferedInputStream等类的方式继承FilterInputStream并实现里面的方法。这种类似的convension对于OutputStream也类似。

    OutputStream的类结构图如下:

     和前面一样,大同小异的结构。

Reader/Writer

     Reader/Writer和前面不一样的地方在于他们是面向具体字符串的。在一定程度上他们要关注传输访问的内容。比如说前面的IOStream只要把一串字节给读过来就可以了,而这里要考虑到编码和具体内容的问题。在很多时候我们读写一些文本内容就需要用到这些。

    下面分别是Reader和Writer的类结构:

 

 

 

File

     和前面两种io方式不一样的地方是,前面的两种方式提供了一个比较高层别的抽象。他们访问的是面向流或者字符的输入输出接口。可以是文件,但是也可以是其他的,比如说USB口,网络socket接口等。而这里对于纯文件的访问,有一个专门的类就是File。

    我们使用File的时候更多的是考虑对于一个个的具体文件来说,要看他们的具体属性,比如说产生和修改时间,文件大小,文件目录结构和层级等。所以说在一些比较直接对文件操作的场景下,它们是最常用的。

    在用File类遍历文件目录的时候会突然有一种想法,感觉就是这里目录和文件是一种树形的结构,目录包含文件或者目录。我们也可以将目录当作一种文件来看,它只是一个其他文件的容器而已。File类是一个相对比较独立的类。由于File相对比较简单,就不详细讨论它的具体使用和实现了。

总结

    我们通常使用的java io主要包含面向流的输入输出(InputStream, OutputStream)以及面向字符的输入输出(Reader, Writer)。采用的这两种输入输出的方式有一个重要的好处就是他们提供了足够的抽象,我们读写的对象可以不仅仅只是单纯的文件,可也以是网络socket, url,也可以是磁盘的块设备或者其他字符串等输入。因为这种抽象涵盖的意义是这么广,它的设计思想有点像unix里面的设计哲学,将各种复杂的输入输出都归结到一种统一的形式,方便使用和扩展。除了以上提到的这两种,如果我们需要对文件操作的话,最常用的是使用File或者RandomAccessFile对象。比如遍历文件或者访问文件某些内容。

    我们前面访问io是采用阻塞式的,也就是说如果我们有一个线程去访问文件或者网络socket等,因为在内存中执行的线程速度和其他IO设备之间访问速度有很大的差别。这就导致io要执行完毕的时候而系统内的线程已经等了好一阵了。于是为了提高线程运行的效率引入了nio。这是一种非阻塞式的io。它可以保证当一个线程执行io的时候,在io执行完毕之前的这段时间它可以继续做自己的事情。关于nio的详细介绍我们会在后面有专门的文章讨论。

参考材料

openjdk

  • 大小: 73.1 KB
  • 大小: 62.9 KB
  • 大小: 38.9 KB
  • 大小: 30.6 KB
分享到:
评论

相关推荐

    Java I/O总结

    Java I/O总结  从new BufferedReader(new InputStreamReader(conn.getInputStream()))想到的  Java I/O总结——InputStream  Java I/O总结——OutputStream  Java I/O总结——Reader  Java I/O总结——...

    java I/O内容

    这是一个关于Java I/O的知识点总结,希望大家共同学习,共同进步

    Java中的I/O学习总结

    Java中的I/O学习总结Java中的I/O学习总结

    java I/O流总结

    这是一篇关于javaSe的基础班关于IO流的全套总结,希望能对你的基础学习有所帮助。

    java数据流 I/O系统

    描述java的I/o系统,描述了java中文件系统的处理,数据流的处理

    JavaIO总结

    有关Java输入输出流的总结有关Java输入输出流的总结有关Java输入输出流的总结

    Java_IO详细教程

    从new BufferedReader(new InputStreamReader(conn.... Java I/O总结——InputStream  Java I/O总结——OutputStream  Java I/O总结——Reader  Java I/O总结——Writer  Java I/O总结——补充说明

    Java知识点总结大全(五) -- IO流.xmind

    Java知识点总结大全(五) -- io流,关注后面会分享面向对象,io,集合,多线程,网络,sql的总结

    Java_IO总结.pdf

    Java_IO总结.pdf Java_IO总结.pdf

    Java OOP 总结

    ACCP6.0 java OOP 总结,里面总结了一些这本书的知识,概括性的把书本上的知识点提炼总结,有些概念性的,标题性居多。

    IO流的使用,自己的心得

    System.arraycopy(writeStringToBytes, i*tempLength, temp, 0, writeStringToBytes.length%tempLength); ops.write(new String(temp,"GBK").trim().getBytes(),0,writeStringToBytes.length%tempLength);...

    java IO流总结.md

    java I/O流的总结 1.操作数据单位:字节流、字符流 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理 对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,...),使用字节流处理 2.数据的流向:输入流、输出流 ...

    基于I/O流设计的图书馆管理系统

    这个是我基于I/O流设计的图书馆管理系统项目总结,是有篇文章的,如果实在不会整再来下载这个完整的。文章:https://blog.csdn.net/GB__LaoWang/article/details/115914058

    Java_IO操作总结

    详解Java I/O相关知识点.学习Java语言IO的数据流概念,讲述了每个类的具体应用范围,IO基本概念,输入输出流的处理,并且给出众多的实例代码。 。

    很全面的资料:Linux之I/O端口

    都是本人以前进行嵌入式项目开发时,总结并整理得来的资料,个人认为很全面,已经尽量用通俗的语言把各个知识点简单化,这也是资源分高达10分的原因之一,另外就是因为转行做java,需要从csdn下载资料,本人的资源分...

    Java 基础核心总结_.zip

    从java概述》java开发环境配置》java基本语法》java执行流程》面向对象》访问控制权限》接口和抽象类》异常》内部类》集合》泛形》反射》枚举》I/O》注解》关于 null 的几种处理方式

    java各知识点详细总结.docx

    Java中的文件读写可以通过Java I/O API来实现。 多线程编程:Java中的多线程编程是一种实现并发程序的方法。Java中的多线程通过创建线程对象和实现Runnable接口来实现。多线程编程可以提高程序的并发性和效率。 网络...

    java深度历险

    序 1 目录 2 JAVA字节代码的操纵 4 动态编译JAVA源文件 4 ...JAVA I/O 45 流 45 缓冲区 47 字符与编码 48 通道 49 参考资料 52 JAVA安全 53 认证 53 权限控制 55 加密、解密与签名 57 安全套接字连接 58 参考资料 59

    java基础学习总结

    &lt;&lt;java基础&gt;&gt; 类和对象&gt;&gt; 接口&gt;&gt; 继承&gt;&gt; 异常&gt;&gt; 线程&gt;&gt; &lt;&lt;applet&gt;&gt; &lt;&lt;Color&gt;&gt; &lt;&lt;Collection&gt;&gt; &lt;&lt;I/O流&gt;&gt;

    Java基础核心总结.PDF

    1.java概述 2.java开发环境配置 3.java基本语法 4.java执行控制流程 5.面向对象 6.访问控制权限 7.接口和抽象类 8.异常 9.内部类 10.集合 11.泛形 12.反射 ...14.I/O 15.注解 16.Null值处理 17.思维导图

Global site tag (gtag.js) - Google Analytics