Java IO概述

IO就是输入/输出。Java IO类库基于抽象基础类InputStreamOutputStream构建了一套I/O体系,主要解决从数据源读入数据和将数据写入到目的地问题。我们把数据源和目的地可以理解为IO流的两端。当然,通常情况下,这两端可能是文件或者网络连接。

我们用下面的图描述下,加深理解:

从一种数据源中通过InputStream流对象读入数据到程序内存中




java 讲读取的io生成图片 java io流读取图片_插入图片


当然我们把上面的图再反向流程,就是OutputStream的示意了。


java 讲读取的io生成图片 java io流读取图片_Java_02


其实除了面向字节流的InputStream/OutputStream体系外,Java IO类库还提供了面向字符流的Reader/Writer体系。Reader/Writer继承结构主要是为了国际化,因为它能更好地处理16位的Unicode字符。

在学习是这两套IO流处理体系可以对比参照着学习,因为有好多相似之处。

要理解总体设计

刚开始写IO代码,总被各种IO流类搞得晕头转向。这么多IO相关的类,各种方法,啥时候能记住。

其实只要我们掌握了IO类库的总体设计思路,理解了它的层次脉络之后,就很清晰。知道啥时候用哪些流对象去组合想要的功能就好了,API的话,可以查手册的嘛。

首先从流的流向上可以分为输入流InputStreamReader,输出流OutputStreamWriter。任何从InputStreamReader派生而来的类都有read()基本方法,读取单个字节或字节数组;任何从OutputSteamWriter派生的类都含有write()的基本方法,用于写单个字节或字节数组。

从操作字节还是操作字符的角度,有面向字节流的类,基本都以XxxStream结尾,面向字符流的类都以XxxReader或XxxWriter结尾。当然这两种类型的流是可以转化的,有两个转化流的类,这个后面会说到。

一般在使用IO流的时候会有下面类似代码:

1 FileInputStream inputStream = new FileInputStream(new File("a.txt"));2 BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);

这里其实是一种装饰器模式的使用,IO流体系中使用了装饰器模式包装了各种功能流类。不了解装饰器模式的看下这篇【详解设计模式】-装饰者模式

在Java IO流体系中FilterInputStream/FilterOutStream和FilterReader/FilterWriter就是装饰器模式的接口类,从该类向下包装了一些功能流类。有DataInputStreamBufferedInputStreamLineNumberInputStreamPushbackInputStream等,当然还有输出的功能流类;面向字符的功能流类等。

下面几张图描述了整个IO流的继承体系结构

InputStream流体系


java 讲读取的io生成图片 java io流读取图片_Java_03


在这里插入图片描述

OutputStream流体系


java 讲读取的io生成图片 java io流读取图片_装饰器模式_04


在这里插入图片描述

Reader体系


java 讲读取的io生成图片 java io流读取图片_jsonp 获取图片文件流_05


在这里插入图片描述

Writer体系


java 讲读取的io生成图片 java io流读取图片_java 讲读取的io生成图片_06


在这里插入图片描述

最后再附加一张表加深印象:


java 讲读取的io生成图片 java io流读取图片_Java_07


在这里插入图片描述

File其实是个工具类

File类其实不止是代表一个文件,它也能代表一个目录下的一组文件(代表一个文件路径)。下面我们盘点一下File类中最常用到的一些方法

1File.delete() 删除文件或文件夹目录。 2File.createNewFile() 创建一个新的空文件。 3File.mkdir() 创建一个新的空文件夹。 4File.list() 获取指定目录下的文件和文件夹名称。 5File.listFiles() 获取指定目录下的文件和文件夹对象。 6File.exists() 文件或者文件夹是否存在 7 8String   getAbsolutePath()   // 获取绝对路径 9long   getFreeSpace()       // 返回分区中未分配的字节数。10String   getName()         // 返回文件或文件夹的名称。11String   getParent()         // 返回父目录的路径名字符串;如果没有指定父目录,则返回 null。12File   getParentFile()      // 返回父目录File对象13String   getPath()         // 返回路径名字符串。14long   getTotalSpace()      // 返回此文件分区大小。15long   getUsableSpace()    //返回占用字节数。16int   hashCode()             //文件哈希码。17long   lastModified()       // 返回文件最后一次被修改的时间。18long   length()          // 获取长度,字节数。19boolean canRead()  //判断是否可读20boolean canWrite()  //判断是否可写21boolean isHidden()  //判断是否隐藏222324// 成员函数25static File[]    listRoots()    // 列出可用的文件系统根。26boolean    renameTo(File dest)    // 重命名27boolean    setExecutable(boolean executable)    // 设置执行权限。28boolean    setExecutable(boolean executable, boolean ownerOnly)    // 设置其他所有用户的执行权限。29boolean    setLastModified(long time)       // 设置最后一次修改时间。30boolean    setReadable(boolean readable)    // 设置读权限。31boolean    setReadable(boolean readable, boolean ownerOnly)    // 设置其他所有用户的读权限。32boolean    setWritable(boolean writable)    // 设置写权限。33boolean    setWritable(boolean writable, boolean ownerOnly)    // 设置所有用户的写权限。34

需要注意的是,不同系统对文件路径的分割符表是不一样的,比如Windows中是“”,Linux是“/”。而File类给我们提供了抽象的表示File.separator,屏蔽了系统层的差异。因此平时在代码中不要使用诸如“”这种代表路径,可能造成Linux平台下代码执行错误。

下面是一些示例:

根据传入的规则,遍历得到目录中所有的文件构成的File对象数组

1public class Directory { 2    public static File[] getLocalFiles(File dir, final String regex){ 3        return dir.listFiles(new FilenameFilter() { 4            private Pattern pattern = Pattern.compile(regex); 5            public boolean accept(File dir, String name) { 6                return pattern.matcher(new File(name).getName()).matches(); 7            } 8        }); 9    }1011    // 重载方法12    public static File[] getLocalFiles(String path, final String regex){13        return getLocalFiles(new File(path),regex);14    }1516    public static void main(String[] args) {17        String dir = "d:";18        File[] files = Directory.getLocalFiles(dir,".*.txt");19        for(File file : files){20            System.out.println(file.getAbsolutePath());21        }22    }23}

输出结果:

1d:1.txt2d:新建文本文档.txt

上面的代码中dir.listFiles(FilenameFilter ) 是策略模式的一种实现,而且使用了匿名内部类的方式。

上面的例子是《Java 编程思想》中的示例,这本书中的每个代码示例都很经典,Bruce Eckel大神把面向对象的思想应用的炉火纯青,非常值得细品。