Java IO概述
IO就是输入/输出。Java IO类库基于抽象基础类InputStream和OutputStream构建了一套I/O体系,主要解决从数据源读入数据和将数据写入到目的地问题。我们把数据源和目的地可以理解为IO流的两端。当然,通常情况下,这两端可能是文件或者网络连接。
我们用下面的图描述下,加深理解:
从一种数据源中通过InputStream流对象读入数据到程序内存中
当然我们把上面的图再反向流程,就是OutputStream的示意了。
其实除了面向字节流的InputStream/OutputStream体系外,Java IO类库还提供了面向字符流的Reader/Writer体系。Reader/Writer继承结构主要是为了国际化,因为它能更好地处理16位的Unicode字符。
在学习是这两套IO流处理体系可以对比参照着学习,因为有好多相似之处。
要理解总体设计
刚开始写IO代码,总被各种IO流类搞得晕头转向。这么多IO相关的类,各种方法,啥时候能记住。
其实只要我们掌握了IO类库的总体设计思路,理解了它的层次脉络之后,就很清晰。知道啥时候用哪些流对象去组合想要的功能就好了,API的话,可以查手册的嘛。
首先从流的流向上可以分为输入流InputStream或Reader,输出流OutputStream或Writer。任何从InputStream或Reader派生而来的类都有read()基本方法,读取单个字节或字节数组;任何从OutputSteam或Writer派生的类都含有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就是装饰器模式的接口类,从该类向下包装了一些功能流类。有DataInputStream、BufferedInputStream、LineNumberInputStream、PushbackInputStream等,当然还有输出的功能流类;面向字符的功能流类等。
下面几张图描述了整个IO流的继承体系结构
InputStream流体系
在这里插入图片描述
OutputStream流体系
在这里插入图片描述
Reader体系
在这里插入图片描述
Writer体系
在这里插入图片描述
最后再附加一张表加深印象:
在这里插入图片描述
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大神把面向对象的思想应用的炉火纯青,非常值得细品。